Compare commits
24 Commits
ac4c248175
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
e94d693a39
|
|||
|
7a44660fc1
|
|||
|
9ac3ffa540
|
|||
|
6ccf84be26
|
|||
|
6d9c78d2e1
|
|||
|
4079207a05
|
|||
|
761b084704
|
|||
|
95a4a6930c
|
|||
|
a788a65ba6
|
|||
|
e10c6f5c46
|
|||
|
cd32dff779
|
|||
|
a2f3170ab5
|
|||
|
3d91fb394a
|
|||
|
771a944a13
|
|||
|
542dca8324
|
|||
|
a68ade9efe
|
|||
|
aca9897f44
|
|||
|
9474a516ac
|
|||
|
8ef39ffe48
|
|||
|
b4424a7782
|
|||
|
5843000df6
|
|||
|
9d37e2bfb8
|
|||
|
cde1392e68
|
|||
|
be10375f60
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -158,3 +158,5 @@ cython_debug/
|
||||
.vscode/
|
||||
core/static/admin
|
||||
core/static/debug_toolbar
|
||||
Makefile
|
||||
static/
|
||||
|
||||
26
Makefile
26
Makefile
@@ -1,26 +0,0 @@
|
||||
run:
|
||||
docker-compose --env-file=stack.env up -d
|
||||
|
||||
build:
|
||||
docker-compose --env-file=stack.env build
|
||||
|
||||
stop:
|
||||
docker-compose --env-file=stack.env down
|
||||
|
||||
log:
|
||||
docker-compose --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"
|
||||
|
||||
migrate:
|
||||
docker-compose --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"
|
||||
|
||||
auth:
|
||||
docker-compose --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"
|
||||
26
Makefile-dev
Normal file
26
Makefile-dev
Normal file
@@ -0,0 +1,26 @@
|
||||
run:
|
||||
docker-compose --env-file=stack.env up -d
|
||||
|
||||
build:
|
||||
docker-compose --env-file=stack.env build
|
||||
|
||||
stop:
|
||||
docker-compose --env-file=stack.env down
|
||||
|
||||
log:
|
||||
docker-compose --env-file=stack.env logs -f
|
||||
|
||||
test:
|
||||
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 --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py migrate"
|
||||
|
||||
makemigrations:
|
||||
docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py makemigrations"
|
||||
|
||||
auth:
|
||||
docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py createsuperuser"
|
||||
|
||||
token:
|
||||
docker-compose --env-file=stack.env run --rm app_dev sh -c ". /venv/bin/activate && python manage.py addstatictoken m"
|
||||
26
Makefile-prod
Normal file
26
Makefile-prod
Normal file
@@ -0,0 +1,26 @@
|
||||
run:
|
||||
docker-compose -f docker-compose.prod.yml --env-file=stack.env up -d
|
||||
|
||||
build:
|
||||
docker-compose -f docker-compose.prod.yml --env-file=stack.env build
|
||||
|
||||
stop:
|
||||
docker-compose -f docker-compose.prod.yml --env-file=stack.env down
|
||||
|
||||
log:
|
||||
docker-compose -f docker-compose.prod.yml --env-file=stack.env logs -f
|
||||
|
||||
test:
|
||||
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 -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py migrate"
|
||||
|
||||
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 -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py createsuperuser"
|
||||
|
||||
token:
|
||||
docker-compose -f docker-compose.prod.yml --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py addstatictoken m"
|
||||
@@ -14,6 +14,7 @@ CSRF_TRUSTED_ORIGINS = getenv("CSRF_TRUSTED_ORIGINS", URL).split(",")
|
||||
|
||||
# Stripe
|
||||
BILLING_ENABLED = getenv("BILLING_ENABLED", "false").lower() in trues
|
||||
|
||||
STRIPE_TEST = getenv("STRIPE_TEST", "true").lower() in trues
|
||||
STRIPE_API_KEY_TEST = getenv("STRIPE_API_KEY_TEST", "")
|
||||
STRIPE_PUBLIC_API_KEY_TEST = getenv("STRIPE_PUBLIC_API_KEY_TEST", "")
|
||||
@@ -47,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"]
|
||||
|
||||
@@ -56,23 +56,6 @@ INSTALLED_APPS = [
|
||||
"cachalot",
|
||||
]
|
||||
|
||||
|
||||
# Performance optimisations
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.redis.RedisCache",
|
||||
"LOCATION": "unix:///var/run/socks/redis.sock",
|
||||
"OPTIONS": {
|
||||
"db": "10",
|
||||
"parser_class": "redis.connection.HiredisParser",
|
||||
"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": "unix:///var/run/redis.sock",
|
||||
"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
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.views import LogoutView
|
||||
from django.urls import include, path
|
||||
from django.views.generic import TemplateView
|
||||
from two_factor.urls import urlpatterns as tf_urls
|
||||
|
||||
from core.views import (
|
||||
@@ -45,7 +44,7 @@ urlpatterns = [
|
||||
path("__debug__/", include("debug_toolbar.urls")),
|
||||
path("", base.Home.as_view(), name="home"),
|
||||
# path("callback", Callback.as_view(), name="callback"),
|
||||
# path("billing/", base.Billing.as_view(), name="billing"),
|
||||
path("billing/", base.Billing.as_view(), name="billing"),
|
||||
# path("order/<str:plan_name>/", base.Order.as_view(), name="order"),
|
||||
# path(
|
||||
# "cancel_subscription/<str:plan_name>/",
|
||||
@@ -56,7 +55,7 @@ urlpatterns = [
|
||||
# "success/", TemplateView.as_view(template_name="success.html"), name="success"
|
||||
# ),
|
||||
# path("cancel/", TemplateView.as_view(template_name="cancel.html"), name="cancel"),
|
||||
# path("portal", base.Portal.as_view(), name="portal"),
|
||||
path("portal", base.Portal.as_view(), name="portal"),
|
||||
path("sapp/", admin.site.urls),
|
||||
# 2FA login urls
|
||||
path("", include(tf_urls)),
|
||||
|
||||
@@ -31,18 +31,18 @@ class CustomUserAdmin(UserAdmin):
|
||||
fieldsets = (
|
||||
*UserAdmin.fieldsets,
|
||||
(
|
||||
"Stripe information",
|
||||
{"fields": ("stripe_id",)},
|
||||
),
|
||||
(
|
||||
"Payment information",
|
||||
{
|
||||
"fields": (
|
||||
# "plans",
|
||||
"last_payment",
|
||||
)
|
||||
},
|
||||
"Billing information",
|
||||
{"fields": ("billing_provider_id", "customer_id", "stripe_id")},
|
||||
),
|
||||
# (
|
||||
# "Payment information",
|
||||
# {
|
||||
# "fields": (
|
||||
# # "plans",
|
||||
# "last_payment",
|
||||
# )
|
||||
# },
|
||||
# ),
|
||||
)
|
||||
|
||||
|
||||
|
||||
82
core/exchanges/mexc.py
Normal file
82
core/exchanges/mexc.py
Normal file
File diff suppressed because one or more lines are too long
@@ -1,11 +1,111 @@
|
||||
import stripe
|
||||
from django.conf import settings
|
||||
from lago_python_client import Client
|
||||
from lago_python_client.models import (
|
||||
Charge,
|
||||
Charges,
|
||||
Customer,
|
||||
CustomerBillingConfiguration,
|
||||
Plan,
|
||||
)
|
||||
from lago_python_client.exceptions import LagoApiError
|
||||
from lago_python_client.models import Customer, CustomerBillingConfiguration
|
||||
|
||||
client = Client(api_key=settings.LAGO_API_KEY, api_url=settings.LAGO_URL)
|
||||
|
||||
|
||||
def expand_name(first_name, last_name):
|
||||
"""
|
||||
Convert two name variables into one.
|
||||
Last name without a first name is ignored.
|
||||
:param first_name: The first name
|
||||
:param last_name: The last name
|
||||
:return: A string with the first and last name, or None if both are None
|
||||
"""
|
||||
name = None
|
||||
if first_name:
|
||||
name = first_name
|
||||
# We only want to put the last name if we have a first name
|
||||
if last_name:
|
||||
name += f" {last_name}"
|
||||
return name
|
||||
|
||||
|
||||
def get_or_create(email, first_name, last_name):
|
||||
"""
|
||||
Get a customer ID from Stripe if one with the given email exists.
|
||||
Create a customer if one does not.
|
||||
Raise an exception if two or more customers matching the given email exist.
|
||||
:param email: The email address of the customer
|
||||
:param first_name: The first name of the customer
|
||||
:param last_name: The last name of the customer
|
||||
:return: The customer ID
|
||||
"""
|
||||
# Let's see if we're just missing the ID
|
||||
matching_customers = stripe.Customer.list(email=email, limit=2)
|
||||
if len(matching_customers) == 2:
|
||||
# Something is horribly wrong
|
||||
raise Exception(f"Two customers found for email {email}")
|
||||
|
||||
elif len(matching_customers) == 1:
|
||||
# We found a customer. Let's copy the ID
|
||||
customer = matching_customers["data"][0]
|
||||
customer_id = customer["id"]
|
||||
return customer_id
|
||||
|
||||
else:
|
||||
# We didn't find anything. Create the customer
|
||||
|
||||
# Create a name, since we have 2 variables which could be null
|
||||
name = expand_name(first_name, last_name)
|
||||
cast = {"email": email}
|
||||
if name:
|
||||
cast["name"] = name
|
||||
customer = stripe.Customer.create(**cast)
|
||||
|
||||
return customer.id
|
||||
|
||||
|
||||
def update_customer_fields(user):
|
||||
"""
|
||||
Update the customer fields in Stripe.
|
||||
"""
|
||||
stripe.Customer.modify(user.stripe_id, email=user.email)
|
||||
name = expand_name(user.first_name, user.last_name)
|
||||
stripe.Customer.modify(user.stripe_id, name=name)
|
||||
|
||||
|
||||
def create_or_update_customer(user):
|
||||
"""
|
||||
Create or update a customer in Lago.
|
||||
"""
|
||||
try:
|
||||
customer = client.customers().find(str(user.customer_id))
|
||||
except LagoApiError:
|
||||
customer = None
|
||||
if not customer:
|
||||
customer = Customer(
|
||||
external_id=str(user.customer_id),
|
||||
name=f"{user.first_name} {user.last_name}",
|
||||
)
|
||||
|
||||
customer.external_id = str(user.customer_id)
|
||||
customer.email = user.email
|
||||
customer.name = f"{user.first_name} {user.last_name}"
|
||||
customer.billing_configuration = CustomerBillingConfiguration(
|
||||
payment_provider="stripe",
|
||||
provider_customer_id=str(user.stripe_id),
|
||||
)
|
||||
|
||||
try:
|
||||
created = client.customers().create(customer)
|
||||
except LagoApiError as e:
|
||||
print(e.response)
|
||||
|
||||
lago_id = created.lago_id
|
||||
|
||||
return lago_id
|
||||
|
||||
|
||||
def delete_customer(user):
|
||||
"""
|
||||
Delete a customer from Lago.
|
||||
:param user: User object to delete
|
||||
"""
|
||||
try:
|
||||
client.customers().destroy(str(user.customer_id))
|
||||
except LagoApiError:
|
||||
pass
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# import logging
|
||||
|
||||
# import stripe
|
||||
|
||||
# logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# def expand_name(first_name, last_name):
|
||||
# """
|
||||
# Convert two name variables into one.
|
||||
# Last name without a first name is ignored.
|
||||
# """
|
||||
# name = None
|
||||
# if first_name:
|
||||
# name = first_name
|
||||
# # We only want to put the last name if we have a first name
|
||||
# if last_name:
|
||||
# name += f" {last_name}"
|
||||
# return name
|
||||
|
||||
|
||||
# def get_or_create(email, first_name, last_name):
|
||||
# """
|
||||
# Get a customer ID from Stripe if one with the given email exists.
|
||||
# Create a customer if one does not.
|
||||
# Raise an exception if two or more customers matching the given email exist.
|
||||
# """
|
||||
# # Let's see if we're just missing the ID
|
||||
# matching_customers = stripe.Customer.list(email=email, limit=2)
|
||||
# if len(matching_customers) == 2:
|
||||
# # Something is horribly wrong
|
||||
# logger.error(f"Two customers found for email {email}")
|
||||
# raise Exception(f"Two customers found for email {email}")
|
||||
|
||||
# elif len(matching_customers) == 1:
|
||||
# # We found a customer. Let's copy the ID
|
||||
# customer = matching_customers["data"][0]
|
||||
# customer_id = customer["id"]
|
||||
# return customer_id
|
||||
|
||||
# else:
|
||||
# # We didn't find anything. Create the customer
|
||||
|
||||
# # Create a name, since we have 2 variables which could be null
|
||||
# name = expand_name(first_name, last_name)
|
||||
# cast = {"email": email}
|
||||
# if name:
|
||||
# cast["name"] = name
|
||||
# customer = stripe.Customer.create(**cast)
|
||||
# logger.info(f"Created new Stripe customer {customer.id} with email {email}")
|
||||
|
||||
# return customer.id
|
||||
|
||||
|
||||
# def update_customer_fields(stripe_id, email=None, first_name=None, last_name=None):
|
||||
# """
|
||||
# Update the customer fields in Stripe.
|
||||
# """
|
||||
# if email:
|
||||
# stripe.Customer.modify(stripe_id, email=email)
|
||||
# logger.info(f"Modified Stripe customer {stripe_id} to have email {email}")
|
||||
# if first_name or last_name:
|
||||
# name = expand_name(first_name, last_name)
|
||||
# stripe.Customer.modify(stripe_id, name=name)
|
||||
# logger.info(f"Modified Stripe customer {stripe_id} to have email {name}")
|
||||
@@ -1,6 +1,7 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from elastic_transport import ConnectionError
|
||||
from elasticsearch import Elasticsearch
|
||||
|
||||
from core.util import logs
|
||||
@@ -22,11 +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()
|
||||
result = client.index(index=index, body=msg)
|
||||
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}")
|
||||
|
||||
@@ -1 +1 @@
|
||||
from core.lib.schemas import alpaca_s, drakdoo_s, oanda_s # noqa
|
||||
from core.lib.schemas import alpaca_s, drakdoo_s, oanda_s, mexc_s # noqa
|
||||
|
||||
1
core/lib/schemas/mexc_s.py
Normal file
1
core/lib/schemas/mexc_s.py
Normal file
@@ -0,0 +1 @@
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -1,29 +1,30 @@
|
||||
from decimal import Decimal as D
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PositionLong(BaseModel):
|
||||
units: str
|
||||
averagePrice: str | None
|
||||
averagePrice: Optional[str] = None
|
||||
pl: str
|
||||
resettablePL: str
|
||||
financing: str
|
||||
dividendAdjustment: str
|
||||
guaranteedExecutionFees: str
|
||||
tradeIDs: list[str] | None
|
||||
tradeIDs: Optional[list[str]] = []
|
||||
unrealizedPL: str
|
||||
|
||||
|
||||
class PositionShort(BaseModel):
|
||||
units: str
|
||||
averagePrice: str | None
|
||||
averagePrice: Optional[str] = None
|
||||
pl: str
|
||||
resettablePL: str
|
||||
financing: str
|
||||
dividendAdjustment: str
|
||||
guaranteedExecutionFees: str
|
||||
tradeIDs: list[str] | None
|
||||
tradeIDs: Optional[list[str]] = []
|
||||
unrealizedPL: str
|
||||
|
||||
|
||||
@@ -306,7 +307,7 @@ class PositionDetailsNested(BaseModel):
|
||||
dividendAdjustment: str
|
||||
guaranteedExecutionFees: str
|
||||
unrealizedPL: str
|
||||
marginUsed: str | None
|
||||
marginUsed: Optional[str] = None
|
||||
|
||||
|
||||
class PositionDetails(BaseModel):
|
||||
@@ -373,7 +374,9 @@ class Instrument(BaseModel):
|
||||
guaranteedStopLossOrderMode: str
|
||||
tags: list[InstrumentTag]
|
||||
financing: InstrumentFinancing
|
||||
guaranteedStopLossOrderLevelRestriction: InstrumentGuaranteedRestriction | None
|
||||
guaranteedStopLossOrderLevelRestriction: Optional[
|
||||
InstrumentGuaranteedRestriction
|
||||
] = None
|
||||
|
||||
|
||||
class AccountInstruments(BaseModel):
|
||||
@@ -474,33 +477,33 @@ class Trade(BaseModel):
|
||||
quoteGuaranteedExecutionFee: str
|
||||
halfSpreadCost: str
|
||||
# takeProfitOrder: TakeProfitOrder | None
|
||||
takeProfitOrder: dict | None
|
||||
stopLossOrder: dict | None
|
||||
trailingStopLossOrder: dict | None
|
||||
takeProfitOrder: Optional[dict] = None
|
||||
stopLossOrder: Optional[dict] = None
|
||||
trailingStopLossOrder: Optional[dict] = None
|
||||
|
||||
|
||||
class SideCarOrder(BaseModel):
|
||||
id: str
|
||||
createTime: str
|
||||
state: str
|
||||
price: str | None
|
||||
price: Optional[str] = None
|
||||
timeInForce: str
|
||||
gtdTime: str | None
|
||||
clientExtensions: dict | None
|
||||
gtdTime: Optional[str] = None
|
||||
clientExtensions: Optional[dict] = None
|
||||
tradeID: str
|
||||
clientTradeID: str | None
|
||||
clientTradeID: Optional[str] = None
|
||||
type: str
|
||||
time: str | None
|
||||
priceBound: str | None
|
||||
positionFill: str | None
|
||||
reason: str | None
|
||||
orderFillTransactionID: str | None
|
||||
tradeOpenedID: str | None
|
||||
tradeReducedID: str | None
|
||||
tradeClosedIDs: list[str] | None
|
||||
cancellingTransactionID: str | None
|
||||
replacesOrderID: str | None
|
||||
replacedByOrderID: str | None
|
||||
time: Optional[str] = None
|
||||
priceBound: Optional[str] = None
|
||||
positionFill: Optional[str] = None
|
||||
reason: Optional[str] = None
|
||||
orderFillTransactionID: Optional[str] = None
|
||||
tradeOpenedID: Optional[str] = None
|
||||
tradeReducedID: Optional[str] = None
|
||||
tradeClosedIDs: Optional[list[str]] = []
|
||||
cancellingTransactionID: Optional[str] = None
|
||||
replacesOrderID: Optional[str] = None
|
||||
replacedByOrderID: Optional[str] = None
|
||||
|
||||
|
||||
class OpenTradesTrade(BaseModel):
|
||||
@@ -517,10 +520,10 @@ class OpenTradesTrade(BaseModel):
|
||||
dividendAdjustment: str
|
||||
unrealizedPL: str
|
||||
marginUsed: str
|
||||
takeProfitOrder: SideCarOrder | None
|
||||
stopLossOrder: SideCarOrder | None
|
||||
trailingStopLossOrder: SideCarOrder | None
|
||||
trailingStopValue: dict | None
|
||||
takeProfitOrder: Optional[SideCarOrder] = None
|
||||
stopLossOrder: Optional[SideCarOrder] = None
|
||||
trailingStopLossOrder: Optional[SideCarOrder] = None
|
||||
trailingStopValue: Optional[dict] = None
|
||||
|
||||
|
||||
class OpenTrades(BaseModel):
|
||||
@@ -578,13 +581,13 @@ class OrderTransaction(BaseModel):
|
||||
requestID: str
|
||||
time: str
|
||||
type: str
|
||||
instrument: str | None
|
||||
units: str | None
|
||||
timeInForce: str | None
|
||||
positionFill: str | None
|
||||
instrument: Optional[str] = None
|
||||
units: Optional[str] = None
|
||||
timeInForce: Optional[str] = None
|
||||
positionFill: Optional[str] = None
|
||||
reason: str
|
||||
longPositionCloseout: LongPositionCloseout | None
|
||||
longOrderFillTransaction: dict | None
|
||||
longOrderFillTransaction: Optional[dict] = None
|
||||
|
||||
|
||||
class OrderCreate(BaseModel):
|
||||
@@ -677,12 +680,12 @@ class TradeDetailsTrade(BaseModel):
|
||||
state: str
|
||||
currentUnits: str
|
||||
realizedPL: str
|
||||
closingTransactionIDs: list[str] | None
|
||||
closingTransactionIDs: Optional[list[str]] = []
|
||||
financing: str
|
||||
dividendAdjustment: str
|
||||
closeTime: str | None
|
||||
averageClosePrice: str | None
|
||||
clientExtensions: ClientExtensions | None
|
||||
closeTime: Optional[str] = None
|
||||
averageClosePrice: Optional[str] = None
|
||||
clientExtensions: Optional[ClientExtensions] = None
|
||||
|
||||
|
||||
class TradeDetails(BaseModel):
|
||||
@@ -733,10 +736,10 @@ TradeCloseSchema = {
|
||||
|
||||
|
||||
class TradeCRCDO(BaseModel):
|
||||
takeProfitOrderCancelTransaction: OrderTransaction
|
||||
takeProfitOrderTransaction: OrderTransaction
|
||||
stopLossOrderCancelTransaction: OrderTransaction
|
||||
stopLossOrderTransaction: OrderTransaction
|
||||
takeProfitOrderCancelTransaction: Optional[OrderTransaction]
|
||||
takeProfitOrderTransaction: Optional[OrderTransaction]
|
||||
stopLossOrderCancelTransaction: Optional[OrderTransaction]
|
||||
stopLossOrderTransaction: Optional[OrderTransaction]
|
||||
relatedTransactionIDs: list[str]
|
||||
lastTransactionID: str
|
||||
|
||||
|
||||
@@ -38,11 +38,15 @@ class Command(BaseCommand):
|
||||
|
||||
log.debug(f"Scheduling checking process job every {INTERVAL} seconds")
|
||||
scheduler.add_job(job, "interval", seconds=INTERVAL)
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
scheduler._eventloop = loop
|
||||
scheduler.start()
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_forever()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
log.info("Process terminating")
|
||||
finally:
|
||||
scheduler.shutdown(wait=False)
|
||||
loop.close()
|
||||
|
||||
@@ -30,8 +30,7 @@ class Migration(migrations.Migration):
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('stripe_id', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('last_payment', models.DateTimeField(blank=True, null=True)),
|
||||
('billing_provider_id', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('email', models.EmailField(max_length=254, unique=True)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
],
|
||||
@@ -44,32 +43,6 @@ class Migration(migrations.Migration):
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Plan',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True)),
|
||||
('description', models.CharField(blank=True, max_length=1024, null=True)),
|
||||
('cost', models.IntegerField()),
|
||||
('product_id', models.CharField(blank=True, max_length=255, null=True, unique=True)),
|
||||
('image', models.CharField(blank=True, max_length=1024, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Session',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('request', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('subscription_id', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('plan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.plan')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='plans',
|
||||
field=models.ManyToManyField(blank=True, to='core.plan'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='user_permissions',
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-24 13:18
|
||||
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('exchange', models.CharField(choices=[('alpaca', 'Alpaca'), ('oanda', 'OANDA'), ('fake', 'Fake')], max_length=255)),
|
||||
('api_key', models.CharField(max_length=255)),
|
||||
('api_secret', models.CharField(max_length=255)),
|
||||
('sandbox', models.BooleanField(default=False)),
|
||||
('enabled', models.BooleanField(default=True)),
|
||||
('supported_symbols', models.JSONField(default=list)),
|
||||
('instruments', models.JSONField(default=list)),
|
||||
('currency', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('initial_balance', models.FloatField(default=0)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ActiveManagementPolicy',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('when_trading_time_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_trends_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_position_size_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only'), ('adjust', 'Adjust violating trades')], default='none', max_length=255)),
|
||||
('when_protection_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only'), ('adjust', 'Adjust violating trades')], default='none', max_length=255)),
|
||||
('when_asset_groups_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_max_open_trades_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_max_open_trades_per_symbol_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_max_loss_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_max_risk_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('when_crossfilter_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AssetGroup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('webhook_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||
('when_no_data', models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=7)),
|
||||
('when_no_match', models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=6)),
|
||||
('when_no_aggregation', models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=6)),
|
||||
('when_not_in_bounds', models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=6)),
|
||||
('when_bullish', models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=2)),
|
||||
('when_bearish', models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=3)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Hook',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=1024)),
|
||||
('hook', models.CharField(max_length=255, unique=True)),
|
||||
('received', models.IntegerField(default=0)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OrderSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('order_type', models.CharField(choices=[('market', 'Market'), ('limit', 'Limit')], default='market', max_length=255)),
|
||||
('time_in_force', models.CharField(choices=[('gtc', 'GTC (Good Til Cancelled)'), ('gfd', 'GFD (Good For Day)'), ('fok', 'FOK (Fill Or Kill)'), ('ioc', 'IOC (Immediate Or Cancel)')], default='gtc', max_length=255)),
|
||||
('take_profit_percent', models.FloatField(default=1.5)),
|
||||
('stop_loss_percent', models.FloatField(default=1.0)),
|
||||
('trailing_stop_loss_percent', models.FloatField(blank=True, default=1.0, null=True)),
|
||||
('trade_size_percent', models.FloatField(default=0.5)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RiskModel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('max_loss_percent', models.FloatField(default=0.05)),
|
||||
('max_risk_percent', models.FloatField(default=0.05)),
|
||||
('max_open_trades', models.IntegerField(default=10)),
|
||||
('max_open_trades_per_symbol', models.IntegerField(default=2)),
|
||||
('price_slippage_percent', models.FloatField(default=2.5)),
|
||||
('callback_price_deviation_percent', models.FloatField(default=0.5)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Signal',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=1024)),
|
||||
('signal', models.CharField(max_length=256)),
|
||||
('direction', models.CharField(choices=[('buy', 'Buy'), ('sell', 'Sell')], max_length=255)),
|
||||
('received', models.IntegerField(default=0)),
|
||||
('type', models.CharField(choices=[('entry', 'Entry'), ('exit', 'Exit'), ('trend', 'Trend')], max_length=255)),
|
||||
('hook', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.hook')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TradingTime',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('start_day', models.IntegerField(choices=[(1, 'Monday'), (2, 'Tuesday'), (3, 'Wednesday'), (4, 'Thursday'), (5, 'Friday'), (6, 'Saturday'), (7, 'Sunday')])),
|
||||
('end_day', models.IntegerField(choices=[(1, 'Monday'), (2, 'Tuesday'), (3, 'Wednesday'), (4, 'Thursday'), (5, 'Friday'), (6, 'Saturday'), (7, 'Sunday')])),
|
||||
('start_time', models.TimeField()),
|
||||
('end_time', models.TimeField()),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Trade',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('symbol', models.CharField(max_length=255)),
|
||||
('time_in_force', models.CharField(choices=[('gtc', 'GTC (Good Til Cancelled)'), ('gfd', 'GFD (Good For Day)'), ('fok', 'FOK (Fill Or Kill)'), ('ioc', 'IOC (Immediate Or Cancel)')], default='gtc', max_length=255)),
|
||||
('type', models.CharField(choices=[('market', 'Market'), ('limit', 'Limit')], max_length=255)),
|
||||
('amount', models.FloatField(blank=True, null=True)),
|
||||
('amount_usd', models.FloatField(blank=True, null=True)),
|
||||
('price', models.FloatField(blank=True, null=True)),
|
||||
('stop_loss', models.FloatField(blank=True, null=True)),
|
||||
('trailing_stop_loss', models.FloatField(blank=True, null=True)),
|
||||
('take_profit', models.FloatField(blank=True, null=True)),
|
||||
('status', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('information', models.JSONField(blank=True, null=True)),
|
||||
('direction', models.CharField(choices=[('buy', 'Buy'), ('sell', 'Sell')], max_length=255)),
|
||||
('order_id', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('client_order_id', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('response', models.JSONField(blank=True, null=True)),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.account')),
|
||||
('hook', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.hook')),
|
||||
('signal', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.signal')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Strategy',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('enabled', models.BooleanField(default=False)),
|
||||
('signal_trading_enabled', models.BooleanField(default=False)),
|
||||
('active_management_enabled', models.BooleanField(default=False)),
|
||||
('trends', models.JSONField(blank=True, null=True)),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.account')),
|
||||
('active_management_policy', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.activemanagementpolicy')),
|
||||
('asset_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.assetgroup')),
|
||||
('entry_signals', models.ManyToManyField(blank=True, related_name='entry_strategies', to='core.signal')),
|
||||
('exit_signals', models.ManyToManyField(blank=True, related_name='exit_strategies', to='core.signal')),
|
||||
('order_settings', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='core.ordersettings')),
|
||||
('risk_model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.riskmodel')),
|
||||
('trading_times', models.ManyToManyField(to='core.tradingtime')),
|
||||
('trend_signals', models.ManyToManyField(blank=True, related_name='trend_strategies', to='core.signal')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'strategies',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='NotificationSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('ntfy_topic', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('ntfy_url', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Callback',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(blank=True, max_length=1024, null=True)),
|
||||
('message', models.CharField(blank=True, max_length=1024, null=True)),
|
||||
('period', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('sent', models.BigIntegerField(blank=True, null=True)),
|
||||
('trade', models.BigIntegerField(blank=True, null=True)),
|
||||
('exchange', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('base', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('quote', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('contract', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('price', models.FloatField(blank=True, null=True)),
|
||||
('symbol', models.CharField(max_length=255)),
|
||||
('hook', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.hook')),
|
||||
('signal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.signal')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AssetRule',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('asset', models.CharField(max_length=64)),
|
||||
('aggregation', models.CharField(choices=[('none', 'None'), ('avg_sentiment', 'Average sentiment')], default='none', max_length=255)),
|
||||
('value', models.FloatField(blank=True, null=True)),
|
||||
('original_status', models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Bullish'), (3, 'Bearish'), (4, 'No aggregation'), (5, 'Not in bounds'), (6, 'Always allow'), (7, 'Always deny')], default=0)),
|
||||
('status', models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Bullish'), (3, 'Bearish'), (4, 'No aggregation'), (5, 'Not in bounds'), (6, 'Always allow'), (7, 'Always deny')], default=0)),
|
||||
('trigger_below', models.FloatField(blank=True, null=True)),
|
||||
('trigger_above', models.FloatField(blank=True, null=True)),
|
||||
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.assetgroup')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('asset', 'group')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,25 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-14 23:15
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0002_session_session'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Hook',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(blank=True, max_length=1024, null=True)),
|
||||
('hook', models.CharField(max_length=255)),
|
||||
('received', models.IntegerField(default=0)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
20
core/migrations/0003_user_customer_id.py
Normal file
20
core/migrations/0003_user_customer_id.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-24 13:21
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0002_account_activemanagementpolicy_assetgroup_hook_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='customer_id',
|
||||
field=models.UUIDField(blank=True, default=uuid.uuid4, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-15 18:19
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0003_hook'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Callback',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('data', models.JSONField()),
|
||||
('hook', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.hook')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 4.0.6 on 2022-10-12 09:08
|
||||
# Generated by Django 4.1.7 on 2023-02-24 16:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
@@ -6,13 +6,13 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
('core', '0003_user_customer_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='session',
|
||||
name='session',
|
||||
model_name='user',
|
||||
name='stripe_id',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,77 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-15 22:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_callback'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='callback',
|
||||
name='data',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='market',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='market_contract',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='market_currency',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='market_exchange',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='market_item',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='message',
|
||||
field=models.CharField(blank=True, max_length=1024, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='period',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='timestamp_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='timestamp_trade',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='title',
|
||||
field=models.CharField(blank=True, max_length=1024, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='hook',
|
||||
name='hook',
|
||||
field=models.CharField(max_length=255, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='hook',
|
||||
name='name',
|
||||
field=models.CharField(blank=True, max_length=1024, null=True, unique=True),
|
||||
),
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-16 13:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0005_remove_callback_data_callback_market_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='callback',
|
||||
name='market',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='callback',
|
||||
name='timestamp_sent',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='callback',
|
||||
name='timestamp_trade',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-17 17:18
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0006_remove_callback_market_alter_callback_timestamp_sent_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('exchange', models.CharField(max_length=255)),
|
||||
('api_key', models.CharField(max_length=255)),
|
||||
('api_secret', models.CharField(max_length=255)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,28 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-17 17:39
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0007_account'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Trade',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('symbol', models.CharField(max_length=255)),
|
||||
('type', models.CharField(max_length=255)),
|
||||
('amount', models.FloatField()),
|
||||
('price', models.FloatField()),
|
||||
('stop_loss', models.FloatField(blank=True, null=True)),
|
||||
('take_profit', models.FloatField(blank=True, null=True)),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.account')),
|
||||
('hook', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.hook')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-17 18:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0008_trade'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='exchange_id',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-17 18:18
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0009_trade_exchange_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='sandbox',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='direction',
|
||||
field=models.CharField(blank=True, choices=[('buy', 'Buy'), ('sell', 'Sell')], max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='symbol',
|
||||
field=models.CharField(choices=[('BTCUSD', 'Bitcoin/USD')], max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('market', 'Market'), ('limit', 'Limit')], max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-18 08:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0010_account_sandbox_trade_direction_trade_status_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='account',
|
||||
name='exchange',
|
||||
field=models.CharField(choices=[('binance', 'Binance'), ('alpaca', 'Alpaca')], max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-18 13:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0011_alter_account_exchange'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='trade',
|
||||
old_name='exchange_id',
|
||||
new_name='client_order_id',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='order_id',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='response',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='symbol',
|
||||
field=models.CharField(choices=[('BTC/USD', 'Bitcoin/US Dollar'), ('LTC/USD', 'Litecoin/US Dollar')], max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,24 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-18 13:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0012_rename_exchange_id_trade_client_order_id_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='direction',
|
||||
field=models.CharField(choices=[('buy', 'Buy'), ('sell', 'Sell')], default='buy', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='price',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-21 22:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0013_alter_trade_direction_alter_trade_price'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='account',
|
||||
name='exchange',
|
||||
field=models.CharField(choices=[('alpaca', 'Alpaca')], max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-25 21:08
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0014_alter_account_exchange'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Strategy',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('enabled', models.BooleanField(default=False)),
|
||||
('take_profit_percent', models.FloatField(default=300.0)),
|
||||
('stop_loss_percent', models.FloatField(default=100.0)),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.account')),
|
||||
('hooks', models.ManyToManyField(to='core.hook')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-25 21:26
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0015_strategy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='user',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='user',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,24 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-26 09:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0016_strategy_user_trade_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='hook',
|
||||
name='direction',
|
||||
field=models.CharField(choices=[('buy', 'Buy'), ('sell', 'Sell')], default='buy', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='price_slippage_percent',
|
||||
field=models.FloatField(default=2.5),
|
||||
),
|
||||
]
|
||||
@@ -1,28 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-26 09:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0017_hook_direction_strategy_price_slippage_percent'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='trade_size_percent',
|
||||
field=models.FloatField(default=2.5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='amount_usd',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='amount',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-27 16:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0018_strategy_trade_size_percent_trade_amount_usd_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='supported_symbols',
|
||||
field=models.JSONField(default=list),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='stop_loss_percent',
|
||||
field=models.FloatField(default=1.0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='take_profit_percent',
|
||||
field=models.FloatField(default=3.0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='trade',
|
||||
name='symbol',
|
||||
field=models.CharField(max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,54 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-10-27 16:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0019_account_supported_symbols_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='callback',
|
||||
old_name='market_item',
|
||||
new_name='base',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='callback',
|
||||
old_name='market_contract',
|
||||
new_name='contract',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='callback',
|
||||
old_name='market_exchange',
|
||||
new_name='exchange',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='callback',
|
||||
old_name='market_currency',
|
||||
new_name='quote',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='callback',
|
||||
old_name='timestamp_sent',
|
||||
new_name='sent',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='callback',
|
||||
old_name='timestamp_trade',
|
||||
new_name='trade',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='price',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='symbol',
|
||||
field=models.CharField(default='NUL/NUL', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-10 18:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0020_rename_market_item_callback_base_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='instruments',
|
||||
field=models.JSONField(default=list),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='account',
|
||||
name='exchange',
|
||||
field=models.CharField(choices=[('alpaca', 'Alpaca'), ('oanda', 'OANDA')], max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='take_profit_percent',
|
||||
field=models.FloatField(default=1.5),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='trade_size_percent',
|
||||
field=models.FloatField(default=0.5),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-10 18:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0021_account_instruments_alter_account_exchange_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='currency',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-15 15:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0022_account_currency'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='strategy',
|
||||
options={'verbose_name_plural': 'strategies'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='callback_price_deviation_percent',
|
||||
field=models.FloatField(default=0.5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='order_type',
|
||||
field=models.CharField(choices=[('market', 'Market'), ('limit', 'Limit')], default='market', max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-15 15:18
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0023_alter_strategy_options_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='time_in_force',
|
||||
field=models.CharField(choices=[('gtc', 'Good Til Cancelled'), ('gfd', 'Good For Day'), ('fok', 'Fill Or Kill'), ('ioc', 'Immediate Or Cancel')], default='gtc', max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-15 15:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0024_strategy_time_in_force'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='time_in_force',
|
||||
field=models.CharField(choices=[('gtc', 'GTC (Good Til Cancelled)'), ('gfd', 'GFD (Good For Day)'), ('fok', 'FOK (Fill Or Kill)'), ('ioc', 'IOC (Immediate Or Cancel)')], default='gtc', max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-15 15:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0025_alter_strategy_time_in_force'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='time_in_force',
|
||||
field=models.CharField(choices=[('gtc', 'GTC (Good Til Cancelled)'), ('gfd', 'GFD (Good For Day)'), ('fok', 'FOK (Fill Or Kill)'), ('ioc', 'IOC (Immediate Or Cancel)')], default='gtc', max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-15 15:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0026_trade_time_in_force'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='trailing_stop_loss_percent',
|
||||
field=models.FloatField(blank=True, default=1.0, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='trailing_stop_loss',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 17:39
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0027_strategy_trailing_stop_loss_percent_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='TradingTime',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('start_ts', models.DateTimeField()),
|
||||
('end_ts', models.DateTimeField()),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 17:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0028_tradingtime'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='name',
|
||||
field=models.CharField(default='DEFAULT', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,45 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 17:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0029_alter_tradingtime_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='tradingtime',
|
||||
name='end_ts',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='tradingtime',
|
||||
name='start_ts',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='tradingtime',
|
||||
name='end_day',
|
||||
field=models.CharField(choices=[('monday', 'Monday'), ('tuesday', 'Tuesday'), ('wednesday', 'Wednesday'), ('thursday', 'Thursday'), ('friday', 'Friday'), ('saturday', 'Saturday'), ('sunday', 'Sunday')], default='monday', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='tradingtime',
|
||||
name='end_time',
|
||||
field=models.TimeField(default='12:00'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='tradingtime',
|
||||
name='start_day',
|
||||
field=models.CharField(choices=[('monday', 'Monday'), ('tuesday', 'Tuesday'), ('wednesday', 'Wednesday'), ('thursday', 'Thursday'), ('friday', 'Friday'), ('saturday', 'Saturday'), ('sunday', 'Sunday')], default='monday', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='tradingtime',
|
||||
name='start_time',
|
||||
field=models.TimeField(default='12:00'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 18:03
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0030_remove_tradingtime_end_ts_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='trading_times',
|
||||
field=models.ManyToManyField(blank=True, to='core.tradingtime'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 18:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0031_strategy_trading_times'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='end_day',
|
||||
field=models.CharField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')], max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='start_day',
|
||||
field=models.CharField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')], max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 18:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0032_alter_tradingtime_end_day_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='end_day',
|
||||
field=models.IntegerField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='start_day',
|
||||
field=models.IntegerField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')]),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 18:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0033_alter_tradingtime_end_day_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='trading_times',
|
||||
field=models.ManyToManyField(to='core.tradingtime'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-11-25 19:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0034_alter_strategy_trading_times'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='end_day',
|
||||
field=models.IntegerField(choices=[(1, 'Monday'), (2, 'Tuesday'), (3, 'Wednesday'), (4, 'Thursday'), (5, 'Friday'), (6, 'Saturday'), (7, 'Sunday')]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tradingtime',
|
||||
name='start_day',
|
||||
field=models.IntegerField(choices=[(1, 'Monday'), (2, 'Tuesday'), (3, 'Wednesday'), (4, 'Thursday'), (5, 'Friday'), (6, 'Saturday'), (7, 'Sunday')]),
|
||||
),
|
||||
]
|
||||
@@ -1,37 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 18:22
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0035_alter_tradingtime_end_day_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='hook',
|
||||
name='direction',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='hook',
|
||||
name='name',
|
||||
field=models.CharField(default='Unknown', max_length=1024),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Signal',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=1024)),
|
||||
('signal', models.CharField(max_length=256)),
|
||||
('direction', models.CharField(choices=[('buy', 'Buy'), ('sell', 'Sell')], max_length=255)),
|
||||
('received', models.IntegerField(default=0)),
|
||||
('hook', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.hook')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 18:33
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0036_remove_hook_direction_alter_hook_name_signal'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='callback',
|
||||
name='signal',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.signal'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 18:40
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0037_callback_signal'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='hooks',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='entry_signals',
|
||||
field=models.ManyToManyField(related_name='entry_strategies', to='core.signal'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='exit_signals',
|
||||
field=models.ManyToManyField(related_name='exit_signals', to='core.signal'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='signal',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.signal'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 18:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0038_remove_strategy_hooks_strategy_entry_signals_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='exit_signals',
|
||||
field=models.ManyToManyField(related_name='exit_strategies', to='core.signal'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 18:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0039_alter_strategy_exit_signals'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='entry_signals',
|
||||
field=models.ManyToManyField(blank=True, null=True, related_name='entry_strategies', to='core.signal'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='exit_signals',
|
||||
field=models.ManyToManyField(blank=True, null=True, related_name='exit_strategies', to='core.signal'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 18:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0040_alter_strategy_entry_signals_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='entry_signals',
|
||||
field=models.ManyToManyField(blank=True, related_name='entry_strategies', to='core.signal'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='strategy',
|
||||
name='exit_signals',
|
||||
field=models.ManyToManyField(blank=True, related_name='exit_strategies', to='core.signal'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-01 19:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0041_alter_strategy_entry_signals_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='trade',
|
||||
name='information',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-06 19:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0042_trade_information'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='trend_signals',
|
||||
field=models.ManyToManyField(blank=True, related_name='trend_strategies', to='core.signal'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-06 19:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0043_strategy_trend_signals'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='trends',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-07 09:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0044_strategy_trends'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='hook',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('entry', 'Entry'), ('exit', 'Exit'), ('trend', 'Trend')], default='entry', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-07 10:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0045_hook_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='hook',
|
||||
name='type',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signal',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('entry', 'Entry'), ('exit', 'Exit'), ('trend', 'Trend')], default='entry', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,24 +0,0 @@
|
||||
# Generated by Django 4.1.3 on 2022-12-18 17:10
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0046_remove_hook_type_signal_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NotificationSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('ntfy_topic', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('ntfy_url', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 4.1.4 on 2022-12-21 21:43
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0047_notificationsettings'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='RiskModel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('max_loss_percent', models.FloatField(default=0.05)),
|
||||
('max_risk_percent', models.FloatField(default=0.05)),
|
||||
('max_open_trades', models.IntegerField(default=10)),
|
||||
('max_open_trades_per_symbol', models.IntegerField(default=2)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='riskmodel',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.riskmodel'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.4 on 2022-12-21 21:51
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0048_riskmodel_account_riskmodel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='account',
|
||||
old_name='riskmodel',
|
||||
new_name='risk_model',
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.4 on 2023-01-01 15:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0049_rename_riskmodel_account_risk_model'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='enabled',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.4 on 2023-01-11 17:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0050_account_enabled'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='initial_balance',
|
||||
field=models.FloatField(default=0),
|
||||
),
|
||||
]
|
||||
@@ -1,37 +0,0 @@
|
||||
# Generated by Django 4.1.4 on 2023-02-10 13:29
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0051_account_initial_balance'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AssetGroup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('allowed', models.JSONField(blank=True, null=True)),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.account')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AssetRestriction',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('pairs', models.CharField(blank=True, max_length=4096, null=True)),
|
||||
('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.assetgroup')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.4 on 2023-02-10 13:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0052_assetgroup_assetrestriction'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetrestriction',
|
||||
name='pairs_parsed',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='allowed',
|
||||
field=models.JSONField(blank=True, default={}, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,25 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-10 21:07
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0053_assetrestriction_pairs_parsed_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetrestriction',
|
||||
name='webhook_id',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='allowed',
|
||||
field=models.JSONField(blank=True, default=dict, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-10 22:57
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0054_assetrestriction_webhook_id_alter_assetgroup_allowed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='asset_group',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.assetgroup'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-10 23:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0055_strategy_asset_group'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assetrestriction',
|
||||
name='pairs_parsed',
|
||||
field=models.JSONField(blank=True, default=dict, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,24 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-11 18:17
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0056_alter_assetrestriction_pairs_parsed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='account',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.account'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetrestriction',
|
||||
name='pairs_parsed',
|
||||
field=models.JSONField(blank=True, default=list, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-11 18:46
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0057_alter_assetgroup_account_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='assetgroup',
|
||||
name='account',
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 10:28
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0058_remove_assetgroup_account'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='webhook_id',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='AssetRestriction',
|
||||
),
|
||||
]
|
||||
@@ -1,28 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 10:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0059_assetgroup_webhook_id_delete_assetrestriction'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='aggregation',
|
||||
field=models.CharField(choices=[('none', 'None'), ('avg_sentiment', 'Average sentiment')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='trigger_above',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='trigger_below',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 18:56
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0060_assetgroup_aggregation_assetgroup_trigger_above_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AssetRule',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('asset', models.CharField(max_length=64)),
|
||||
('aggregation', models.CharField(choices=[('none', 'None'), ('avg_sentiment', 'Average sentiment')], default='none', max_length=255)),
|
||||
('value', models.FloatField(blank=True, null=True)),
|
||||
('status', models.FloatField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Positive'), (3, 'Negative')], default=0)),
|
||||
('trigger_below', models.FloatField(blank=True, null=True)),
|
||||
('trigger_above', models.FloatField(blank=True, null=True)),
|
||||
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.assetgroup')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 18:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0061_assetrule'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assetrule',
|
||||
name='status',
|
||||
field=models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Positive'), (3, 'Negative')], default=0),
|
||||
),
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 19:03
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0062_alter_assetrule_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='assetrule',
|
||||
unique_together={('asset', 'group')},
|
||||
),
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 19:28
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0063_alter_assetrule_unique_together'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='assetgroup',
|
||||
name='aggregation',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='assetgroup',
|
||||
name='allowed',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='assetgroup',
|
||||
name='trigger_above',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='assetgroup',
|
||||
name='trigger_below',
|
||||
),
|
||||
]
|
||||
@@ -1,53 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-13 20:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0064_remove_assetgroup_aggregation_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='when_bearish',
|
||||
field=models.IntegerField(choices=[(6, 'Ignore (no action)'), (-1, 'Default (no remapping)'), (2, 'Bullish'), (3, 'Bearish')], default=-1, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='when_bullish',
|
||||
field=models.IntegerField(choices=[(6, 'Ignore (no action)'), (-1, 'Default (no remapping)'), (2, 'Bullish'), (3, 'Bearish')], default=-1, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='when_no_aggregation',
|
||||
field=models.IntegerField(choices=[(6, 'Ignore (no action)'), (-1, 'Default (no remapping)'), (2, 'Bullish'), (3, 'Bearish')], default=-1, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='when_no_data',
|
||||
field=models.IntegerField(choices=[(6, 'Ignore (no action)'), (-1, 'Default (no remapping)'), (2, 'Bullish'), (3, 'Bearish')], default=-1, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='when_no_match',
|
||||
field=models.IntegerField(choices=[(6, 'Ignore (no action)'), (-1, 'Default (no remapping)'), (2, 'Bullish'), (3, 'Bearish')], default=-1, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetgroup',
|
||||
name='when_not_in_bounds',
|
||||
field=models.IntegerField(choices=[(6, 'Ignore (no action)'), (-1, 'Default (no remapping)'), (2, 'Bullish'), (3, 'Bearish')], default=-1, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetrule',
|
||||
name='original_status',
|
||||
field=models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Bullish'), (3, 'Bearish'), (4, 'No aggregation'), (5, 'Not in bounds'), (6, 'No action')], default=0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetrule',
|
||||
name='status',
|
||||
field=models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Bullish'), (3, 'Bearish'), (4, 'No aggregation'), (5, 'Not in bounds'), (6, 'No action')], default=0),
|
||||
),
|
||||
]
|
||||
@@ -1,81 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-15 18:11
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0065_assetgroup_when_bearish_assetgroup_when_bullish_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='risk_model',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='callback_price_deviation_percent',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='price_slippage_percent',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='riskmodel',
|
||||
name='callback_price_deviation_percent',
|
||||
field=models.FloatField(default=0.5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='riskmodel',
|
||||
name='price_slippage_percent',
|
||||
field=models.FloatField(default=2.5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='risk_model',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.riskmodel'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='when_bearish',
|
||||
field=models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=3),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='when_bullish',
|
||||
field=models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=2),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='when_no_aggregation',
|
||||
field=models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=6),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='when_no_data',
|
||||
field=models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=7),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='when_no_match',
|
||||
field=models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=6),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='when_not_in_bounds',
|
||||
field=models.IntegerField(choices=[(6, 'Always allow'), (7, 'Always deny'), (2, 'Bullish'), (3, 'Bearish')], default=6),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetrule',
|
||||
name='original_status',
|
||||
field=models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Bullish'), (3, 'Bearish'), (4, 'No aggregation'), (5, 'Not in bounds'), (6, 'Always allow'), (7, 'Always deny')], default=0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetrule',
|
||||
name='status',
|
||||
field=models.IntegerField(choices=[(0, 'No data'), (1, 'No match'), (2, 'Bullish'), (3, 'Bearish'), (4, 'No aggregation'), (5, 'Not in bounds'), (6, 'Always allow'), (7, 'Always deny')], default=0),
|
||||
),
|
||||
]
|
||||
@@ -1,30 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-15 18:31
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0066_remove_account_risk_model_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OrderSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('order_type', models.CharField(choices=[('market', 'Market'), ('limit', 'Limit')], default='market', max_length=255)),
|
||||
('time_in_force', models.CharField(choices=[('gtc', 'GTC (Good Til Cancelled)'), ('gfd', 'GFD (Good For Day)'), ('fok', 'FOK (Fill Or Kill)'), ('ioc', 'IOC (Immediate Or Cancel)')], default='gtc', max_length=255)),
|
||||
('take_profit_percent', models.FloatField(default=1.5)),
|
||||
('stop_loss_percent', models.FloatField(default=1.0)),
|
||||
('trailing_stop_loss_percent', models.FloatField(blank=True, default=1.0, null=True)),
|
||||
('trade_size_percent', models.FloatField(default=0.5)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-15 18:34
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0067_ordersettings_strategy_order_settings'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='order_settings',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, to='core.ordersettings'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,37 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-15 19:12
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0068_strategy_order_settings'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='order_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='stop_loss_percent',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='take_profit_percent',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='time_in_force',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='trade_size_percent',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='strategy',
|
||||
name='trailing_stop_loss_percent',
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-15 19:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0069_remove_strategy_order_type_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='active_management_enabled',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='signal_trading_enabled',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -1,30 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-17 11:50
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0070_strategy_active_management_enabled_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='account',
|
||||
name='exchange',
|
||||
field=models.CharField(choices=[('alpaca', 'Alpaca'), ('oanda', 'OANDA'), ('fake', 'Fake')], max_length=255),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ActiveManagementPolicy',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('when_trading_time_violated', models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,58 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-17 11:58
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0071_alter_account_exchange_activemanagementpolicy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_asset_groups_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_crossfilter_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_max_loss_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_max_open_trades_per_symbol_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_max_open_trades_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_max_risk_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_position_size_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only'), ('adjust', 'Adjust violating trades')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_protection_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only'), ('adjust', 'Adjust violating trades')], default='none', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='activemanagementpolicy',
|
||||
name='when_trends_violated',
|
||||
field=models.CharField(choices=[('none', 'None'), ('close', 'Close violating trades'), ('notify', 'Notify only')], default='none', max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-17 13:16
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0072_activemanagementpolicy_when_asset_groups_violated_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='strategy',
|
||||
name='active_management_policy',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.activemanagementpolicy'),
|
||||
),
|
||||
]
|
||||
@@ -1,42 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-24 12:20
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0073_strategy_active_management_policy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='session',
|
||||
name='plan',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='session',
|
||||
name='user',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='user',
|
||||
old_name='stripe_id',
|
||||
new_name='billing_provider_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='user',
|
||||
name='last_payment',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='user',
|
||||
name='plans',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Plan',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Session',
|
||||
),
|
||||
]
|
||||
@@ -1,20 +1,27 @@
|
||||
import uuid
|
||||
from datetime import timedelta
|
||||
|
||||
# import stripe
|
||||
# from django.conf import settings
|
||||
import stripe
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
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
|
||||
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"),
|
||||
@@ -79,6 +86,14 @@ ADJUST_CLOSE_NOTIFY_CHOICES = (
|
||||
("adjust", "Adjust violating trades"),
|
||||
)
|
||||
|
||||
ADJUST_WITH_DIRECTION_CHOICES = (
|
||||
("none", "None"),
|
||||
("close", "Close violating trades"),
|
||||
("notify", "Notify only"),
|
||||
("adjust", "Increase and reduce"),
|
||||
("adjust_up", "Increase only"),
|
||||
("adjust_down", "Reduce only"),
|
||||
)
|
||||
|
||||
# class Plan(models.Model):
|
||||
# name = models.CharField(max_length=255, unique=True)
|
||||
@@ -93,21 +108,38 @@ ADJUST_CLOSE_NOTIFY_CHOICES = (
|
||||
|
||||
class User(AbstractUser):
|
||||
# Stripe customer ID
|
||||
# unique_id = models.UUIDField(
|
||||
# default=uuid.uuid4,
|
||||
# )
|
||||
# stripe_id = models.CharField(max_length=255, null=True, blank=True)
|
||||
stripe_id = models.CharField(max_length=255, null=True, blank=True)
|
||||
customer_id = models.UUIDField(default=uuid.uuid4, null=True, blank=True)
|
||||
billing_provider_id = models.CharField(max_length=255, null=True, blank=True)
|
||||
# last_payment = models.DateTimeField(null=True, blank=True)
|
||||
# plans = models.ManyToManyField(Plan, blank=True)
|
||||
email = models.EmailField(unique=True)
|
||||
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# super().__init__(*args, **kwargs)
|
||||
# self._original = self
|
||||
def delete(self, *args, **kwargs):
|
||||
if settings.BILLING_ENABLED:
|
||||
if self.stripe_id:
|
||||
stripe.Customer.delete(self.stripe_id)
|
||||
log.info(f"Deleted Stripe customer {self.stripe_id}")
|
||||
if self.billing_provider_id:
|
||||
billing.delete_customer(self)
|
||||
log.info(f"Deleted Billing customer {self.billing_provider_id}")
|
||||
super().delete(*args, **kwargs)
|
||||
|
||||
# Override save to update attributes in Lago
|
||||
def save(self, *args, **kwargs):
|
||||
if self.customer_id is None:
|
||||
self.customer_id = uuid.uuid4()
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
if not self.stripe_id: # stripe ID not stored
|
||||
self.stripe_id = billing.get_or_create(
|
||||
self.email, self.first_name, self.last_name
|
||||
)
|
||||
if not self.billing_provider_id:
|
||||
self.billing_provider_id = billing.create_or_update_customer(self)
|
||||
|
||||
billing.update_customer_fields(self)
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_notification_settings(self):
|
||||
@@ -115,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)
|
||||
@@ -139,11 +176,13 @@ class Account(models.Model):
|
||||
if client:
|
||||
response = client.get_instruments()
|
||||
supported_symbols = client.get_supported_assets(response)
|
||||
currency = client.get_account()["currency"]
|
||||
acct_info = client.get_account()
|
||||
log.debug(f"Supported symbols for {self.name}: {supported_symbols}")
|
||||
self.supported_symbols = supported_symbols
|
||||
self.instruments = response
|
||||
self.currency = currency
|
||||
if "currency" in acct_info.keys():
|
||||
currency = acct_info["currency"]
|
||||
self.currency = currency
|
||||
if save:
|
||||
self.save()
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
{% endif %}
|
||||
{% if settings.BILLING_ENABLED %}
|
||||
{% if user.is_authenticated %}
|
||||
<a class="navbar-item" href="{# url 'billing' #}">
|
||||
<a class="navbar-item" href="{% url 'billing' %}">
|
||||
Billing
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -311,7 +311,10 @@
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<a class="button" href="{% url 'logout' %}">Logout</a>
|
||||
<form method="POST" action="{% url 'logout' %}" style="display:inline;">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="button">Logout</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -10,20 +10,6 @@
|
||||
</span>
|
||||
<span class="tag">{{ user.first_name }} {{ user.last_name }}</span>
|
||||
</a>
|
||||
<a class="panel-block">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-binary" aria-hidden="true"></i>
|
||||
</span>
|
||||
{% for plan in user.plans.all %}
|
||||
<span class="tag">{{ plan.name }}</span>
|
||||
{% endfor %}
|
||||
</a>
|
||||
<a class="panel-block">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-credit-card" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="tag">{{ user.last_payment }}</span>
|
||||
</a>
|
||||
<a class="panel-block" href="{% url 'portal' %}">
|
||||
<span class="panel-icon">
|
||||
<i class="fa-brands fa-stripe-s" aria-hidden="true"></i>
|
||||
|
||||
@@ -283,6 +283,15 @@ class ActiveManagementTestCase(StrategyMixin, SymbolPriceMock, TestCase):
|
||||
},
|
||||
)
|
||||
|
||||
def test_position_size_violated_increase_only(self):
|
||||
pass
|
||||
|
||||
def test_position_size_violated_decrease_only(self):
|
||||
pass
|
||||
|
||||
def test_position_size_violated_increase_decrease(self):
|
||||
pass
|
||||
|
||||
def test_protection_violated(self):
|
||||
self.trades[0]["takeProfitOrder"] = {"price": "0.0001"}
|
||||
self.trades[0]["stopLossOrder"] = {"price": "0.0001"}
|
||||
|
||||
@@ -203,6 +203,15 @@ class ActiveManagementLiveTestCase(ElasticMock, StrategyMixin, LiveBase, TestCas
|
||||
trades = self.account.client.get_all_open_trades()
|
||||
self.assertEqual(len(trades), 0)
|
||||
|
||||
def test_ams_position_size_violated_increase(self):
|
||||
pass
|
||||
|
||||
def test_ams_position_size_violated_decrease(self):
|
||||
pass
|
||||
|
||||
def test_ams_position_size_violated_increase_decrease(self):
|
||||
pass
|
||||
|
||||
def test_ams_protection_violated(self):
|
||||
self.active_management_policy.when_protection_violated = "close"
|
||||
self.active_management_policy.save()
|
||||
@@ -413,8 +422,6 @@ class ActiveManagementLiveTestCase(ElasticMock, StrategyMixin, LiveBase, TestCas
|
||||
},
|
||||
]
|
||||
}
|
||||
print("ACTIONS", self.ams.actions)
|
||||
print("EXP", expected)
|
||||
|
||||
self.assertEqual(self.ams.actions, expected)
|
||||
|
||||
|
||||
@@ -44,6 +44,13 @@ def check_max_risk(risk_model, account_balance_usd, account_trades):
|
||||
return allowed
|
||||
|
||||
|
||||
def check_max_trade_risk(risk_model, account_balance_usd, trade):
|
||||
"""
|
||||
Check that the trade is within the max trade risk percentage of the account size.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def check_max_open_trades(risk_model, account_trades):
|
||||
"""
|
||||
Check that the number of trades in the account is within the max open trades limit.
|
||||
|
||||
@@ -30,7 +30,7 @@ class AccountInfo(LoginRequiredMixin, OTPRequiredMixin, ObjectRead):
|
||||
"sandbox",
|
||||
"supported_symbols",
|
||||
"initial_balance",
|
||||
"instruments",
|
||||
#"instruments",
|
||||
]
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user