diff --git a/Makefile-dev b/Makefile-dev index e4db8cb..78f3afe 100644 --- a/Makefile-dev +++ b/Makefile-dev @@ -1,26 +1,26 @@ run: - docker-compose -f docker-compose.dev.yml --env-file=stack.env up -d + docker-compose --env-file=stack.env up -d build: - docker-compose -f docker-compose.dev.yml --env-file=stack.env build + docker-compose --env-file=stack.env build stop: - docker-compose -f docker-compose.dev.yml --env-file=stack.env down + docker-compose --env-file=stack.env down log: - docker-compose -f docker-compose.dev.yml --env-file=stack.env logs -f + docker-compose --env-file=stack.env logs -f test: - docker-compose -f docker-compose.dev.yml --env-file=stack.env run -e LIVE=$(LIVE) --rm app_dev sh -c ". /venv/bin/activate && python manage.py test $(MODULES) -v 2" + docker-compose --env-file=stack.env run -e LIVE=$(LIVE) --rm app_dev sh -c ". /venv/bin/activate && python manage.py test $(MODULES) -v 2" migrate: - docker-compose -f docker-compose.dev.yml --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py migrate" + docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py migrate" makemigrations: - docker-compose -f docker-compose.dev.yml --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py makemigrations" + docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py makemigrations" auth: - docker-compose -f docker-compose.dev.yml --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py createsuperuser" + docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py createsuperuser" token: - docker-compose -f docker-compose.dev.yml --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py addstatictoken m" + docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py addstatictoken m" diff --git a/Makefile-prod b/Makefile-prod index 934ed54..b493c80 100644 --- a/Makefile-prod +++ b/Makefile-prod @@ -1,26 +1,26 @@ run: - docker-compose --env-file=stack.env up -d + docker-compose -f docker-compose.prod.yml --env-file=stack.env up -d build: - docker-compose --env-file=stack.env build + docker-compose -f docker-compose.prod.yml --env-file=stack.env build stop: - docker-compose --env-file=stack.env down + docker-compose -f docker-compose.prod.yml --env-file=stack.env down log: - docker-compose --env-file=stack.env logs -f + docker-compose -f docker-compose.prod.yml --env-file=stack.env logs -f test: - docker-compose --env-file=stack.env run -e LIVE=$(LIVE) --rm app sh -c ". /venv/bin/activate && python manage.py test $(MODULES) -v 2" + docker-compose -f docker-compose.prod.yml --env-file=stack.env run -e LIVE=$(LIVE) --rm app sh -c ". /venv/bin/activate && python manage.py test $(MODULES) -v 2" migrate: - docker-compose --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py migrate" + docker-compose -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py migrate" makemigrations: - docker-compose --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py makemigrations" + docker-compose -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py makemigrations" auth: - docker-compose --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py createsuperuser" + docker-compose -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py createsuperuser" token: - docker-compose --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py addstatictoken m" + docker-compose -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py addstatictoken m" diff --git a/app/local_settings.py b/app/local_settings.py index 7c12d13..b8c4b91 100644 --- a/app/local_settings.py +++ b/app/local_settings.py @@ -48,13 +48,18 @@ LAGO_URL = getenv("LAGO_URL", "") DEBUG = getenv("DEBUG", "false").lower() in trues PROFILER = getenv("PROFILER", "false").lower() in trues +REDIS_HOST = getenv("REDIS_HOST", "redis_fisk_dev") +REDIS_PASSWORD = getenv("REDIS_PASSWORD", "changeme") +REDIS_DB = int(getenv("REDIS_DB", "10")) +REDIS_PORT = int(getenv("REDIS_PORT", "6379")) + if DEBUG: import socket # only if you haven't already imported this hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + [ "127.0.0.1", - "10.0.2.2", + # "10.0.2.2", ] SETTINGS_EXPORT = ["BILLING_ENABLED", "URL", "HOOK_PATH", "ASSET_PATH"] diff --git a/app/settings.py b/app/settings.py index 17898d6..5817bf8 100644 --- a/app/settings.py +++ b/app/settings.py @@ -56,23 +56,6 @@ INSTALLED_APPS = [ "cachalot", ] - -# Performance optimisations -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": "unix:///var/run/socks/redis.sock", - "OPTIONS": { - "db": "10", - # "parser_class": "django_redis.cache.RedisCache", - "pool_class": "redis.BlockingConnectionPool", - }, - } -} -# CACHE_MIDDLEWARE_ALIAS = 'default' -# CACHE_MIDDLEWARE_SECONDS = '600' -# CACHE_MIDDLEWARE_KEY_PREFIX = '' - CRISPY_TEMPLATE_PACK = "bulma" CRISPY_ALLOWED_TEMPLATE_PACKS = ("bulma",) DJANGO_TABLES2_TEMPLATE = "django-tables2/bulma.html" @@ -184,7 +167,7 @@ REST_FRAMEWORK = { INTERNAL_IPS = [ "127.0.0.1", - "10.1.10.11", + # "10.1.10.11", ] DEBUG_TOOLBAR_PANELS = [ @@ -208,6 +191,24 @@ DEBUG_TOOLBAR_PANELS = [ from app.local_settings import * # noqa +# Performance optimisations +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + # "LOCATION": "unix:///var/run/socks/redis.sock", + "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}", + "OPTIONS": { + "db": REDIS_DB, + # "parser_class": "django_redis.cache.RedisCache", + "PASSWORD": REDIS_PASSWORD, + "pool_class": "redis.BlockingConnectionPool", + }, + } +} +# CACHE_MIDDLEWARE_ALIAS = 'default' +# CACHE_MIDDLEWARE_SECONDS = '600' +# CACHE_MIDDLEWARE_KEY_PREFIX = '' + if PROFILER: # noqa - trust me its there import pyroscope diff --git a/core/__init__.py b/core/__init__.py index 8743bfb..d1d0e50 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,4 +1,5 @@ import os + import stripe from django.conf import settings diff --git a/core/exchanges/mexc.py b/core/exchanges/mexc.py new file mode 100644 index 0000000..b04ad17 --- /dev/null +++ b/core/exchanges/mexc.py @@ -0,0 +1,69 @@ +from core.exchanges import BaseExchange, common +from core.util import logs + +from pymexc import spot, futures + +log = logs.get_logger("mexc") + + +class MEXCExchange(BaseExchange): + def call_method(self, request): + ... + + def connect(self): + self.client = spot.HTTP( + api_key=self.account.api_key, + api_secret=self.account.api_key + ) + + def get_account(self): + r = self.client.account_information() + print("ACC INFO", r) + + def get_instruments(self): + ... + + def get_currencies(self, currencies): + ... + + def get_supported_assets(self, response=None): + ... + + def get_balance(self, return_usd=False): + ... + + def get_market_value(self, symbol): + raise NotImplementedError + + def post_trade(self, trade): + ... + + def get_trade_precision(self, symbol): + ... + + def close_trade(self, trade_id, units=None, symbol=None): + ... + + def get_trade(self, trade_id): + ... + + def update_trade(self, trade_id, take_profit_price, stop_loss_price): + ... + + def cancel_trade(self, trade_id): + ... + + def get_position_info(self, symbol): + ... + + def get_all_positions(self): + ... + + def get_all_open_trades(self): + ... + + def close_position(self, side, symbol): + ... + + def close_all_positions(self): + ... diff --git a/core/lib/elastic.py b/core/lib/elastic.py index 6bdab55..b2da508 100644 --- a/core/lib/elastic.py +++ b/core/lib/elastic.py @@ -23,15 +23,16 @@ def initialise_elasticsearch(): def store_msg(index, msg): - global client - if not client: - client = initialise_elasticsearch() - if "ts" not in msg: - msg["ts"] = datetime.utcnow().isoformat() - try: - result = client.index(index=index, body=msg) - except ConnectionError as e: - log.error(f"Error indexing '{msg}': {e}") - return - if not result["result"] == "created": - log.error(f"Indexing of '{msg}' failed: {result}") + return + # global client + # if not client: + # client = initialise_elasticsearch() + # if "ts" not in msg: + # msg["ts"] = datetime.utcnow().isoformat() + # try: + # result = client.index(index=index, body=msg) + # except ConnectionError as e: + # log.error(f"Error indexing '{msg}': {e}") + # return + # if not result["result"] == "created": + # log.error(f"Indexing of '{msg}' failed: {result}") diff --git a/core/lib/schemas/oanda_s.py b/core/lib/schemas/oanda_s.py index 6e86baa..345009d 100644 --- a/core/lib/schemas/oanda_s.py +++ b/core/lib/schemas/oanda_s.py @@ -1,7 +1,8 @@ from decimal import Decimal as D +from typing import Optional from pydantic import BaseModel -from typing import Optional + class PositionLong(BaseModel): units: str @@ -373,7 +374,9 @@ class Instrument(BaseModel): guaranteedStopLossOrderMode: str tags: list[InstrumentTag] financing: InstrumentFinancing - guaranteedStopLossOrderLevelRestriction: Optional[InstrumentGuaranteedRestriction] = None + guaranteedStopLossOrderLevelRestriction: Optional[ + InstrumentGuaranteedRestriction + ] = None class AccountInstruments(BaseModel): diff --git a/core/models.py b/core/models.py index c534bd3..cc483de 100644 --- a/core/models.py +++ b/core/models.py @@ -8,6 +8,7 @@ from django.db import models from core.exchanges.alpaca import AlpacaExchange from core.exchanges.fake import FakeExchange +from core.exchanges.mexc import MEXCExchange from core.exchanges.oanda import OANDAExchange # from core.lib.customers import get_or_create, update_customer_fields @@ -15,7 +16,12 @@ from core.lib import billing from core.util import logs log = logs.get_logger(__name__) -EXCHANGE_MAP = {"alpaca": AlpacaExchange, "oanda": OANDAExchange, "fake": FakeExchange} +EXCHANGE_MAP = { + "alpaca": AlpacaExchange, + "oanda": OANDAExchange, + "mexc": MEXCExchange, + "fake": FakeExchange, +} TYPE_CHOICES = ( ("market", "Market"), ("limit", "Limit"), @@ -141,7 +147,12 @@ class User(AbstractUser): class Account(models.Model): - EXCHANGE_CHOICES = (("alpaca", "Alpaca"), ("oanda", "OANDA"), ("fake", "Fake")) + EXCHANGE_CHOICES = ( + ("alpaca", "Alpaca"), + ("oanda", "OANDA"), + ("mexc", "MEXC"), + ("fake", "Fake"), + ) user = models.ForeignKey(User, on_delete=models.CASCADE) name = models.CharField(max_length=255) exchange = models.CharField(choices=EXCHANGE_CHOICES, max_length=255) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..67210c3 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,316 @@ +version: "2.2" + +services: + app: + image: xf/fisk:prod + container_name: fisk + build: + context: . + args: + OPERATION: ${OPERATION} + volumes: + - ${PORTAINER_GIT_DIR}:/code + - ${PORTAINER_GIT_DIR}/docker/uwsgi.ini:/conf/uwsgi.ini + - ${APP_DATABASE_FILE}:/conf/db.sqlite3 + - fisk_static:${STATIC_ROOT} + #ports: + # - "8000:8000" # uwsgi socket + # Dirty hack for Podman + environment: + APP_PORT: "${APP_PORT}" + PORTAINER_GIT_DIR: "${PORTAINER_GIT_DIR}" + APP_LOCAL_SETTINGS: "${APP_LOCAL_SETTINGS}" + APP_DATABASE_FILE: "${APP_DATABASE_FILE}" + DOMAIN: "${DOMAIN}" + URL: "${URL}" + ALLOWED_HOSTS: "${ALLOWED_HOSTS}" + NOTIFY_TOPIC: "${NOTIFY_TOPIC}" + CSRF_TRUSTED_ORIGINS: "${CSRF_TRUSTED_ORIGINS}" + DEBUG: "${DEBUG}" + SECRET_KEY: "${SECRET_KEY}" + STATIC_ROOT: "${STATIC_ROOT}" + REGISTRATION_OPEN: "${REGISTRATION_OPEN}" + OPERATION: "${OPERATION}" + ELASTICSEARCH_USERNAME: "${ELASTICSEARCH_USERNAME}" + ELASTICSEARCH_PASSWORD: "${ELASTICSEARCH_PASSWORD}" + ELASTICSEARCH_HOST: "${ELASTICSEARCH_HOST}" + ELASTICSEARCH_TLS: "${ELASTICSEARCH_TLS}" + TEST_ACCOUNT_NAME: "${TEST_ACCOUNT_NAME}" + TEST_ACCOUNT_EXCHANGE: "${TEST_ACCOUNT_EXCHANGE}" + TEST_ACCOUNT_API_KEY: "${TEST_ACCOUNT_API_KEY}" + TEST_ACCOUNT_API_SECRET: "${TEST_ACCOUNT_API_SECRET}" + PROFILER: "${PROFILER}" + BILLING_ENABLED: "${BILLING_ENABLED}" + LAGO_API_KEY: "${LAGO_API_KEY}" + LAGO_ORG_ID: "${LAGO_ORG_ID}" + LAGO_URL: "${LAGO_URL}" + STRIPE_TEST: "${STRIPE_TEST}" + STRIPE_API_KEY_TEST: "${STRIPE_API_KEY_TEST}" + STRIPE_PUBLIC_API_KEY_TEST: "${STRIPE_PUBLIC_API_KEY_TEST}" + STRIPE_API_KEY_PROD: "${STRIPE_API_KEY_PROD}" + STRIPE_PUBLIC_API_KEY_PROD: "${STRIPE_PUBLIC_API_KEY_PROD}" + STRIPE_ENDPOINT_SECRET: "${STRIPE_ENDPOINT_SECRET}" + REDIS_HOST: "${REDIS_HOST}" + # env_file: + # - stack.env + # volumes_from: + # - tmp + depends_on: + # redis: + # condition: service_healthy + migration: + condition: service_started + collectstatic: + condition: service_started + networks: + - default + - xf + # - elastic + + scheduling: + image: xf/fisk:prod + container_name: scheduling_fisk + build: + context: . + args: + OPERATION: ${OPERATION} + command: sh -c '. /venv/bin/activate && python manage.py scheduling' + volumes: + - ${PORTAINER_GIT_DIR}:/code + - ${PORTAINER_GIT_DIR}/docker/uwsgi.ini:/conf/uwsgi.ini + - ${APP_DATABASE_FILE}:/conf/db.sqlite3 + - fisk_static:${STATIC_ROOT} + # Dirty hack for Podman + environment: + APP_PORT: "${APP_PORT}" + PORTAINER_GIT_DIR: "${PORTAINER_GIT_DIR}" + APP_LOCAL_SETTINGS: "${APP_LOCAL_SETTINGS}" + APP_DATABASE_FILE: "${APP_DATABASE_FILE}" + DOMAIN: "${DOMAIN}" + URL: "${URL}" + ALLOWED_HOSTS: "${ALLOWED_HOSTS}" + NOTIFY_TOPIC: "${NOTIFY_TOPIC}" + CSRF_TRUSTED_ORIGINS: "${CSRF_TRUSTED_ORIGINS}" + DEBUG: "${DEBUG}" + SECRET_KEY: "${SECRET_KEY}" + STATIC_ROOT: "${STATIC_ROOT}" + REGISTRATION_OPEN: "${REGISTRATION_OPEN}" + OPERATION: "${OPERATION}" + ELASTICSEARCH_USERNAME: "${ELASTICSEARCH_USERNAME}" + ELASTICSEARCH_PASSWORD: "${ELASTICSEARCH_PASSWORD}" + ELASTICSEARCH_HOST: "${ELASTICSEARCH_HOST}" + ELASTICSEARCH_TLS: "${ELASTICSEARCH_TLS}" + TEST_ACCOUNT_NAME: "${TEST_ACCOUNT_NAME}" + TEST_ACCOUNT_EXCHANGE: "${TEST_ACCOUNT_EXCHANGE}" + TEST_ACCOUNT_API_KEY: "${TEST_ACCOUNT_API_KEY}" + TEST_ACCOUNT_API_SECRET: "${TEST_ACCOUNT_API_SECRET}" + PROFILER: "${PROFILER}" + BILLING_ENABLED: "${BILLING_ENABLED}" + LAGO_API_KEY: "${LAGO_API_KEY}" + LAGO_ORG_ID: "${LAGO_ORG_ID}" + LAGO_URL: "${LAGO_URL}" + STRIPE_TEST: "${STRIPE_TEST}" + STRIPE_API_KEY_TEST: "${STRIPE_API_KEY_TEST}" + STRIPE_PUBLIC_API_KEY_TEST: "${STRIPE_PUBLIC_API_KEY_TEST}" + STRIPE_API_KEY_PROD: "${STRIPE_API_KEY_PROD}" + STRIPE_PUBLIC_API_KEY_PROD: "${STRIPE_PUBLIC_API_KEY_PROD}" + STRIPE_ENDPOINT_SECRET: "${STRIPE_ENDPOINT_SECRET}" + REDIS_HOST: "${REDIS_HOST}" + # env_file: + # - stack.env + # volumes_from: + # - tmp + depends_on: + redis: + condition: service_healthy + migration: + condition: service_started + collectstatic: + condition: service_started + networks: + - default + - xf + # - db + + migration: + image: xf/fisk:prod + container_name: migration_fisk + build: + context: . + args: + OPERATION: ${OPERATION} + command: sh -c '. /venv/bin/activate && python manage.py migrate --noinput' + volumes: + - ${PORTAINER_GIT_DIR}:/code + - ${APP_DATABASE_FILE}:/conf/db.sqlite3 + - fisk_static:${STATIC_ROOT} + # volumes_from: + # - tmp + # Dirty hack for Podman + environment: + APP_PORT: "${APP_PORT}" + PORTAINER_GIT_DIR: "${PORTAINER_GIT_DIR}" + APP_LOCAL_SETTINGS: "${APP_LOCAL_SETTINGS}" + APP_DATABASE_FILE: "${APP_DATABASE_FILE}" + DOMAIN: "${DOMAIN}" + URL: "${URL}" + ALLOWED_HOSTS: "${ALLOWED_HOSTS}" + NOTIFY_TOPIC: "${NOTIFY_TOPIC}" + CSRF_TRUSTED_ORIGINS: "${CSRF_TRUSTED_ORIGINS}" + DEBUG: "${DEBUG}" + SECRET_KEY: "${SECRET_KEY}" + STATIC_ROOT: "${STATIC_ROOT}" + REGISTRATION_OPEN: "${REGISTRATION_OPEN}" + OPERATION: "${OPERATION}" + ELASTICSEARCH_USERNAME: "${ELASTICSEARCH_USERNAME}" + ELASTICSEARCH_PASSWORD: "${ELASTICSEARCH_PASSWORD}" + ELASTICSEARCH_HOST: "${ELASTICSEARCH_HOST}" + ELASTICSEARCH_TLS: "${ELASTICSEARCH_TLS}" + TEST_ACCOUNT_NAME: "${TEST_ACCOUNT_NAME}" + TEST_ACCOUNT_EXCHANGE: "${TEST_ACCOUNT_EXCHANGE}" + TEST_ACCOUNT_API_KEY: "${TEST_ACCOUNT_API_KEY}" + TEST_ACCOUNT_API_SECRET: "${TEST_ACCOUNT_API_SECRET}" + PROFILER: "${PROFILER}" + BILLING_ENABLED: "${BILLING_ENABLED}" + LAGO_API_KEY: "${LAGO_API_KEY}" + LAGO_ORG_ID: "${LAGO_ORG_ID}" + LAGO_URL: "${LAGO_URL}" + STRIPE_TEST: "${STRIPE_TEST}" + STRIPE_API_KEY_TEST: "${STRIPE_API_KEY_TEST}" + STRIPE_PUBLIC_API_KEY_TEST: "${STRIPE_PUBLIC_API_KEY_TEST}" + STRIPE_API_KEY_PROD: "${STRIPE_API_KEY_PROD}" + STRIPE_PUBLIC_API_KEY_PROD: "${STRIPE_PUBLIC_API_KEY_PROD}" + STRIPE_ENDPOINT_SECRET: "${STRIPE_ENDPOINT_SECRET}" + REDIS_HOST: "${REDIS_HOST}" + # env_file: + # - stack.env + + collectstatic: + image: xf/fisk:prod + container_name: collectstatic_fisk + build: + context: . + args: + OPERATION: ${OPERATION} + command: sh -c '. /venv/bin/activate && python manage.py collectstatic --noinput' + volumes: + - ${PORTAINER_GIT_DIR}:/code + - ${APP_DATABASE_FILE}:/conf/db.sqlite3 + - fisk_static:${STATIC_ROOT} + # volumes_from: + # - tmp + # Dirty hack for Podman + environment: + APP_PORT: "${APP_PORT}" + PORTAINER_GIT_DIR: "${PORTAINER_GIT_DIR}" + APP_LOCAL_SETTINGS: "${APP_LOCAL_SETTINGS}" + APP_DATABASE_FILE: "${APP_DATABASE_FILE}" + DOMAIN: "${DOMAIN}" + URL: "${URL}" + ALLOWED_HOSTS: "${ALLOWED_HOSTS}" + NOTIFY_TOPIC: "${NOTIFY_TOPIC}" + CSRF_TRUSTED_ORIGINS: "${CSRF_TRUSTED_ORIGINS}" + DEBUG: "${DEBUG}" + SECRET_KEY: "${SECRET_KEY}" + STATIC_ROOT: "${STATIC_ROOT}" + REGISTRATION_OPEN: "${REGISTRATION_OPEN}" + OPERATION: "${OPERATION}" + ELASTICSEARCH_USERNAME: "${ELASTICSEARCH_USERNAME}" + ELASTICSEARCH_PASSWORD: "${ELASTICSEARCH_PASSWORD}" + ELASTICSEARCH_HOST: "${ELASTICSEARCH_HOST}" + ELASTICSEARCH_TLS: "${ELASTICSEARCH_TLS}" + TEST_ACCOUNT_NAME: "${TEST_ACCOUNT_NAME}" + TEST_ACCOUNT_EXCHANGE: "${TEST_ACCOUNT_EXCHANGE}" + TEST_ACCOUNT_API_KEY: "${TEST_ACCOUNT_API_KEY}" + TEST_ACCOUNT_API_SECRET: "${TEST_ACCOUNT_API_SECRET}" + PROFILER: "${PROFILER}" + BILLING_ENABLED: "${BILLING_ENABLED}" + LAGO_API_KEY: "${LAGO_API_KEY}" + LAGO_ORG_ID: "${LAGO_ORG_ID}" + LAGO_URL: "${LAGO_URL}" + STRIPE_TEST: "${STRIPE_TEST}" + STRIPE_API_KEY_TEST: "${STRIPE_API_KEY_TEST}" + STRIPE_PUBLIC_API_KEY_TEST: "${STRIPE_PUBLIC_API_KEY_TEST}" + STRIPE_API_KEY_PROD: "${STRIPE_API_KEY_PROD}" + STRIPE_PUBLIC_API_KEY_PROD: "${STRIPE_PUBLIC_API_KEY_PROD}" + STRIPE_ENDPOINT_SECRET: "${STRIPE_ENDPOINT_SECRET}" + REDIS_HOST: "${REDIS_HOST}" + # env_file: + # - stack.env + + nginx: + image: nginx:latest + container_name: nginx_fisk + ports: + - ${APP_PORT}:9999 + ulimits: + nproc: 65535 + nofile: + soft: 65535 + hard: 65535 + volumes: + - ${PORTAINER_GIT_DIR}:/code + - ${PORTAINER_GIT_DIR}/docker/nginx/conf.d/${OPERATION}.conf:/etc/nginx/conf.d/default.conf + - fisk_static:${STATIC_ROOT} + # volumes_from: + # - tmp + networks: + - default + - xf + depends_on: + app: + condition: service_started + + + # volumes_from: + # - tmp + # depends_on: + # redis: + # condition: service_healthy + + # tmp: + # image: busybox + # container_name: tmp_fisk + # command: chmod -R 777 /var/run/socks + # volumes: + # - /var/run/socks + + # For caching + redis: + image: redis + container_name: redis_fisk + command: redis-server /etc/redis.conf + ulimits: + nproc: 65535 + nofile: + soft: 65535 + hard: 65535 + volumes: + - ${PORTAINER_GIT_DIR}/docker/redis.conf:/etc/redis.conf + - fisk_redis_data:/data + # volumes_from: + # - tmp + healthcheck: + test: "redis-cli ping" + interval: 2s + timeout: 2s + retries: 15 + + # pyroscope: + # image: "pyroscope/pyroscope:latest" + # ports: + # - "4040:4040" + # command: + # - "server" + +networks: + default: + driver: bridge + xf: + external: true + # db: + # external: true + +volumes: + fisk_static: {} + fisk_redis_data: {} diff --git a/docker-compose.yml b/docker-compose.yml index e146517..6d97718 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,11 @@ version: "2.2" - + +name: fisk_dev + services: - app: - image: xf/fisk:prod - container_name: fisk + app_dev: + image: xf/fisk:dev + container_name: fisk_dev build: context: . args: @@ -12,28 +14,28 @@ services: - ${PORTAINER_GIT_DIR}:/code - ${PORTAINER_GIT_DIR}/docker/uwsgi.ini:/conf/uwsgi.ini - ${APP_DATABASE_FILE}:/conf/db.sqlite3 - - fisk_static:${STATIC_ROOT} + - fisk_static_dev:${STATIC_ROOT} #ports: # - "8000:8000" # uwsgi socket env_file: - stack.env - volumes_from: - - tmp + # volumes_from: + # - tmp_dev depends_on: # redis: # condition: service_healthy - migration: + migration_dev: condition: service_started - collectstatic: + collectstatic_dev: condition: service_started networks: - default - xf - - elastic + # - db - scheduling: - image: xf/fisk:prod - container_name: scheduling_fisk + scheduling_dev: + image: xf/fisk:dev + container_name: scheduling_fisk_dev build: context: . args: @@ -43,26 +45,26 @@ services: - ${PORTAINER_GIT_DIR}:/code - ${PORTAINER_GIT_DIR}/docker/uwsgi.ini:/conf/uwsgi.ini - ${APP_DATABASE_FILE}:/conf/db.sqlite3 - - fisk_static:${STATIC_ROOT} + - fisk_static_dev:${STATIC_ROOT} env_file: - stack.env - volumes_from: - - tmp + # volumes_from: + # - tmp_dev depends_on: - redis: + redis_dev: condition: service_healthy - migration: + migration_dev: condition: service_started - collectstatic: + collectstatic_dev: condition: service_started networks: - default - xf - - elastic + # - db - migration: - image: xf/fisk:prod - container_name: migration_fisk + migration_dev: + image: xf/fisk:dev + container_name: migration_fisk_dev build: context: . args: @@ -71,15 +73,15 @@ services: volumes: - ${PORTAINER_GIT_DIR}:/code - ${APP_DATABASE_FILE}:/conf/db.sqlite3 - - fisk_static:${STATIC_ROOT} - volumes_from: - - tmp + - fisk_static_dev:${STATIC_ROOT} + # volumes_from: + # - tmp_dev env_file: - stack.env - collectstatic: - image: xf/fisk:prod - container_name: collectstatic_fisk + collectstatic_dev: + image: xf/fisk:dev + container_name: collectstatic_fisk_dev build: context: . args: @@ -88,15 +90,15 @@ services: volumes: - ${PORTAINER_GIT_DIR}:/code - ${APP_DATABASE_FILE}:/conf/db.sqlite3 - - fisk_static:${STATIC_ROOT} - volumes_from: - - tmp + - fisk_static_dev:${STATIC_ROOT} + # volumes_from: + # - tmp_dev env_file: - stack.env - nginx: + nginx_dev: image: nginx:latest - container_name: nginx_fisk + container_name: nginx_fisk_dev ports: - ${APP_PORT}:9999 ulimits: @@ -107,14 +109,14 @@ services: volumes: - ${PORTAINER_GIT_DIR}:/code - ${PORTAINER_GIT_DIR}/docker/nginx/conf.d/${OPERATION}.conf:/etc/nginx/conf.d/default.conf - - fisk_static:${STATIC_ROOT} - volumes_from: - - tmp + - fisk_static_dev:${STATIC_ROOT} + # volumes_from: + # - tmp_dev networks: - default - xf depends_on: - app: + app_dev: condition: service_started @@ -124,17 +126,17 @@ services: # redis: # condition: service_healthy - tmp: - image: busybox - container_name: tmp_fisk - command: chmod -R 777 /var/run/socks - volumes: - - /var/run/socks + # tmp_dev: + # image: busybox + # container_name: tmp_fisk_dev + # command: chmod -R 777 /var/run/socks + # volumes: + # - /var/run/socks # For caching - redis: + redis_dev: image: redis - container_name: redis_fisk + container_name: redis_fisk_dev command: redis-server /etc/redis.conf ulimits: nproc: 65535 @@ -143,11 +145,11 @@ services: hard: 65535 volumes: - ${PORTAINER_GIT_DIR}/docker/redis.conf:/etc/redis.conf - - fisk_redis_data:/data - volumes_from: - - tmp + - fisk_redis_data_dev:/data + # volumes_from: + # - tmp_dev healthcheck: - test: "redis-cli -s /var/run/socks/redis.sock ping" + test: "redis-cli ping" interval: 2s timeout: 2s retries: 15 @@ -164,9 +166,9 @@ networks: driver: bridge xf: external: true - elastic: - external: true + # db: + # external: true volumes: - fisk_static: {} - fisk_redis_data: {} + fisk_static_dev: {} + fisk_redis_data_dev: {} diff --git a/docker/redis.conf b/docker/redis.conf index 424a612..b4acb37 100644 --- a/docker/redis.conf +++ b/docker/redis.conf @@ -1,2 +1,4 @@ -unixsocket /var/run/socks/redis.sock -unixsocketperm 777 \ No newline at end of file +# unixsocket /var/run/socks/redis.sock +# unixsocketperm 777 +port 6379 +requirepass changeme \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c2fd08c..81d7dac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,8 +17,12 @@ django-otp-yubikey phonenumbers qrcode pydantic +# Alpaca alpaca-py +# OANDA oandapyV20 +# MEXC +pymexc glom elasticsearch apscheduler