Skip to content

A Free-From-Risk crypto trading simulation named KCX(Knightchaser's Cryptocurrency eXchange), built with Svelte + FastAPI + Docker + α

Notifications You must be signed in to change notification settings

KnightChaser/kcx

Repository files navigation

KCX

Knightchaser's Cryptocurrency eXchange

TECH STACK

  • Service buildup

sveltekit_lgo vite_logo nodejs_logo jwt_logo fastapi_logo sqlite_logo redis_logo nginx_logo

  • Deployment

docker_logo aws_logo

  • You can able to deploy on

windows_logo ubuntu_logo

A Free-From-Risk cryptocurrency exchange simulation web application

You can try KCX at https://kcx.knightchaser.com/, hosted via AWS Lightsail by the repository owner. Note that the specifications, service status, and other things might be changed depending on the development contexts and situations. (Try only for fun! :D)

Notice of public service discontinuation

The KCX service on the AWS LightSail has been discontinued since Sep. 3, 2024 due to financial issues. During the services with 87 days, 3,566 transactions worth 16.7 trillion KRW(12.525 billion US$) were made(If all money in the services were REAL). Thanks for loving this project, my first attempt to make a modern website!

Service environmental variables

Currently, there are environment variables to set up the services as you need. Read the next chapter(Deployment) for complete contextual information.

SQLALCHEMY_DB_SQLITE3_FILENAME="kcx.db"

TEST_ACCOUNT_ID="test"
TEST_ACCOUNT_PW="test"
TEST_ACCOUNT_EMAIL="[email protected]"
COMMON_STARTING_BALANCE_IN_KRW=20000000000 # 20 billion KRW

# An example SECRET KEY for JWT. Change this to a random in production!
JWT_SECRET_KEY="KCXU$3R$3CR3T4JWT_"
JWT_TOKEN_EXPIRES_MINUTES=360 # 6 hours

# A custom API server built with Redis
REDIS_PORT=6379
REDIS_DB=0
REDIS_UDPATE_INTERVAL_IN_SECONDS=1
USER_RANKING_UPDATE_INTERVAL_IN_SECONDS=10

# Service configuration
# - Money balance (Disable(false) this if you want to use a fixed starting balance for all users)
ALLOW_ARBITRARY_BALANCE_DEPOSIT=false
ALLOW_ARBITRARY_BALANCE_WITHDRAW=false
  • Permanent data for this service will be stored in SQLite3. Configure SQLALCHEMY_DB_SQLITE3_FILENAME to change the filename (if you want).
  • As a default, there are default account settings.
    • The service will create a default account for testing when the service starts. (Will not if it's already created)
    • Configure TEST_ACCOUNT_ID(ID = username), TEST_ACCOUNT_PW(password), and TEST_ACCOUNT_EMAIL(email) for the test account.
    • COMMON_STARTING_BALANCE_IN_KRW defines how much fund will be initially granted to the new user.
  • This server uses JWT for user authentication. Configure JWT_SECRET_KEY for JWT server key(change to another random value or your own) and JWT_TOKEN_EXPIRES_MINUTES for JWT expiary period.
  • For the price information, this service uses the market data provided from UpBIT. Of course this also mimics the cryptocurrency exchange, there are a lot of requests about the crypto market data(Generally 3 to 5 requests per second per connected user) To reduce the direct API request to UpBIT, this use REDIS database as a cache. The server caches the market data every second and multiple connected users obtain the data from this REDIS cache.
    • REDIS_UPDATE_INTERVAL_IN_SECONDS means which second this service refreshes the market data from UpBIT to the REDIS cache periodically. Basically, you can safely request up to 5 requests per second to UpBIT according to the current policy.
    • USER_RANKING_UPDATE_INTERVAL_IN_SECONDS means which second this service calculate the users' ranking data according to the calculated estimated total asset value periodically (for leaderboard). Note that this ranking calculation relatively takes a lot of computational loads(iterating all users and calculating all types of assets for estimation), so don't make it too short.
  • ALLOW_ARBITRARY_BALANCE_* configures whether the user controls their virtual balances on their own. If these are set true, then they can unlimitedly deposit(increase) and withdraw(decrease) the wallet, that may impact on the leaderboard. If you run this service for competitions or some rules, set it to false so no one except for the administrator can control the user's balances. (By accessing the SQLite3 database.)

Plus, there is a feature of sending verification emails for changing account email address/password, or recoverying password. Get a possible SMTP(Simple Mail Transfer Protocol) account, and create the following environment variable file named <PROJECT_DIR>/backend/.secrets.smtp, fill the contents like below. If you use Gmail for SMTP, the configuration would like below.

# backend/.secrets.smtp

SMTP_USERNAME="knightchaser_example"        # Gmail address without "@gmail.com"
SMTP_PASSWORD="abcd efgh ijkl mnop"         # App password
SMTP_SERVER="smtp.gmail.com"
SMTP_PORT=587

Deployment

  • Clone the repository on your server/environments
https://github.com/KnightChaser/kcx.git
  • To intiate the service, you'll have to use docker-compose(Or, docker compose for Docker Compose v2. Not matter which version you use).
  • If you are going to run service locally(such as windows), execute the following commands(the system(Windows/Linux) should be able to operate the docker applications)
docker-compose -f docker-compose.yml build
docker-compose -f docker-compose.yml up -d
  • If you are going to run service globally with TLS/SSL certificates(For production. https://kcx.knightchaser.com is currently running on this way.), check the prerequisites and operate the docker.
    • Ensure that you have your own domain(FQDN) such as *.knightchaser.com and it's registered on the global DNS server. (i.e. Route53 in AWS)
    • Ensure that the valid TLS/SSL certificates are issued and prepared on your system. (i.e. A certificate issued by Certbot via letsencrypt)
    • Ensure that you properly adjusted the settings(described in the next chapter; Note about TLS/SSL.). Then, boot up the service with the following commands.
docker-compose -f docker-compose-server-deploy.yml build
docker-compose -f docker-compose-server-deploy.yml up -d

Service data

  • All service data will be stored in <PROJECT_DIR>/data. Back up this directory periodically in case of deployment!
  • Currently, the data directory will have the following major entires
data
 ┣ database
 ┃ ┗ (SQLite3 database file)
 ┗ uploads
 ┃ ┗ profile_images
 ┃ ┃ ┣ (user profile pictures)
 ...

Note about TLS/SSL

  • The TLS/SSL extensions are expected to be in /etc/letsencrypt in general if you use letsencrypt.
(/etc/letsencrypt)
├── live
│   ├── README
│   └── knightchaser.com
│       ├── README
│       ├── cert.pem -> ../../archive/knightchaser.com/cert1.pem
│       ├── chain.pem -> ../../archive/knightchaser.com/chain1.pem
│       ├── fullchain.pem -> ../../archive/knightchaser.com/fullchain1.pem
│       └── privkey.pem -> ../../archive/knightchaser.com/privkey1.pem
  • In nginx.conf, the basic structure will be the below example. (The given example is https://kcx.knightchaser.com's.) Change server_name, ssl_certificate, and ssl_certificate_key properties to your own.
events { }

http {
    server {
        listen 80;
        server_name kcx.knightchaser.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name kcx.knightchaser.com;

        ssl_certificate /etc/letsencrypt/live/knightchaser.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/knightchaser.com/privkey.pem;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            proxy_pass http://frontend:5173;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /api/ {
            proxy_pass http://backend:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
  • In the Docker compsure file(docker-compose-server-deploy.yml), adjust the volumes part of nginx to yours(if it's needed). If you follow the standard letsencrypt's TLS/SSL issuing procedure with Certbot, this adjustment won't be necessary.
  ...
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - /etc/letsencrypt:/etc/letsencrypt
    depends_on:
      - frontend
      - backend
    networks:
      - kcx-network
  • In <PROJECT_DIR>/frontend/.env(Vite environment variable file), adjust the backend API URL to your domain. Since the suffix string /api is the hardcoded value of this project for consistency, you will only have to adjust the URL part. https://kcx.knightchaser.com part for the example below.
VITE_BACKEND_API_URL="https://kcx.knightchaser.com/api"
  • Miscellaneous: TLS/SSL uses the port 443. Allow 80 and 443 ports at least.

About

A Free-From-Risk crypto trading simulation named KCX(Knightchaser's Cryptocurrency eXchange), built with Svelte + FastAPI + Docker + α

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published