Compare commits
26 Commits
c6dd0ff286
...
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
|
|||
|
ac4c248175
|
|||
|
0937f7299a
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -158,3 +158,5 @@ cython_debug/
|
|||||||
.vscode/
|
.vscode/
|
||||||
core/static/admin
|
core/static/admin
|
||||||
core/static/debug_toolbar
|
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"
|
||||||
@@ -13,7 +13,8 @@ ALLOWED_HOSTS = getenv("ALLOWED_HOSTS", f"127.0.0.1,{DOMAIN}").split(",")
|
|||||||
CSRF_TRUSTED_ORIGINS = getenv("CSRF_TRUSTED_ORIGINS", URL).split(",")
|
CSRF_TRUSTED_ORIGINS = getenv("CSRF_TRUSTED_ORIGINS", URL).split(",")
|
||||||
|
|
||||||
# Stripe
|
# Stripe
|
||||||
STRIPE_ENABLED = getenv("STRIPE_ENABLED", "false").lower() in trues
|
BILLING_ENABLED = getenv("BILLING_ENABLED", "false").lower() in trues
|
||||||
|
|
||||||
STRIPE_TEST = getenv("STRIPE_TEST", "true").lower() in trues
|
STRIPE_TEST = getenv("STRIPE_TEST", "true").lower() in trues
|
||||||
STRIPE_API_KEY_TEST = getenv("STRIPE_API_KEY_TEST", "")
|
STRIPE_API_KEY_TEST = getenv("STRIPE_API_KEY_TEST", "")
|
||||||
STRIPE_PUBLIC_API_KEY_TEST = getenv("STRIPE_PUBLIC_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
|
DEBUG = getenv("DEBUG", "false").lower() in trues
|
||||||
PROFILER = getenv("PROFILER", "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:
|
if DEBUG:
|
||||||
import socket # only if you haven't already imported this
|
import socket # only if you haven't already imported this
|
||||||
|
|
||||||
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||||
INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + [
|
INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + [
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"10.0.2.2",
|
# "10.0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
SETTINGS_EXPORT = ["STRIPE_ENABLED", "URL", "HOOK_PATH", "ASSET_PATH"]
|
SETTINGS_EXPORT = ["BILLING_ENABLED", "URL", "HOOK_PATH", "ASSET_PATH"]
|
||||||
|
|||||||
@@ -56,23 +56,6 @@ INSTALLED_APPS = [
|
|||||||
"cachalot",
|
"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_TEMPLATE_PACK = "bulma"
|
||||||
CRISPY_ALLOWED_TEMPLATE_PACKS = ("bulma",)
|
CRISPY_ALLOWED_TEMPLATE_PACKS = ("bulma",)
|
||||||
DJANGO_TABLES2_TEMPLATE = "django-tables2/bulma.html"
|
DJANGO_TABLES2_TEMPLATE = "django-tables2/bulma.html"
|
||||||
@@ -184,7 +167,7 @@ REST_FRAMEWORK = {
|
|||||||
|
|
||||||
INTERNAL_IPS = [
|
INTERNAL_IPS = [
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"10.1.10.11",
|
# "10.1.10.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
DEBUG_TOOLBAR_PANELS = [
|
DEBUG_TOOLBAR_PANELS = [
|
||||||
@@ -208,6 +191,24 @@ DEBUG_TOOLBAR_PANELS = [
|
|||||||
|
|
||||||
from app.local_settings import * # noqa
|
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
|
if PROFILER: # noqa - trust me its there
|
||||||
import pyroscope
|
import pyroscope
|
||||||
|
|
||||||
|
|||||||
26
app/urls.py
26
app/urls.py
@@ -18,7 +18,6 @@ from django.conf.urls.static import static
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.views import LogoutView
|
from django.contrib.auth.views import LogoutView
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.views.generic import TemplateView
|
|
||||||
from two_factor.urls import urlpatterns as tf_urls
|
from two_factor.urls import urlpatterns as tf_urls
|
||||||
|
|
||||||
from core.views import (
|
from core.views import (
|
||||||
@@ -38,23 +37,24 @@ from core.views import (
|
|||||||
strategies,
|
strategies,
|
||||||
trades,
|
trades,
|
||||||
)
|
)
|
||||||
from core.views.stripe_callbacks import Callback
|
|
||||||
|
# from core.views.stripe_callbacks import Callback
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("__debug__/", include("debug_toolbar.urls")),
|
path("__debug__/", include("debug_toolbar.urls")),
|
||||||
path("", base.Home.as_view(), name="home"),
|
path("", base.Home.as_view(), name="home"),
|
||||||
path("callback", Callback.as_view(), name="callback"),
|
# 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("order/<str:plan_name>/", base.Order.as_view(), name="order"),
|
||||||
path(
|
# path(
|
||||||
"cancel_subscription/<str:plan_name>/",
|
# "cancel_subscription/<str:plan_name>/",
|
||||||
base.Cancel.as_view(),
|
# base.Cancel.as_view(),
|
||||||
name="cancel_subscription",
|
# name="cancel_subscription",
|
||||||
),
|
# ),
|
||||||
path(
|
# path(
|
||||||
"success/", TemplateView.as_view(template_name="success.html"), name="success"
|
# "success/", TemplateView.as_view(template_name="success.html"), name="success"
|
||||||
),
|
# ),
|
||||||
path("cancel/", TemplateView.as_view(template_name="cancel.html"), name="cancel"),
|
# 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),
|
path("sapp/", admin.site.urls),
|
||||||
# 2FA login urls
|
# 2FA login urls
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ from django.contrib import admin
|
|||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
|
|
||||||
from .forms import CustomUserCreationForm
|
from .forms import CustomUserCreationForm
|
||||||
from .models import ( # AssetRestriction,
|
from .models import ( # AssetRestriction,; Plan,; Session,
|
||||||
Account,
|
Account,
|
||||||
AssetGroup,
|
AssetGroup,
|
||||||
Callback,
|
Callback,
|
||||||
Hook,
|
Hook,
|
||||||
NotificationSettings,
|
NotificationSettings,
|
||||||
Plan,
|
|
||||||
RiskModel,
|
RiskModel,
|
||||||
Session,
|
|
||||||
Signal,
|
Signal,
|
||||||
Strategy,
|
Strategy,
|
||||||
Trade,
|
Trade,
|
||||||
@@ -27,24 +25,24 @@ from .models import ( # AssetRestriction,
|
|||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
list_filter = ["plans"]
|
# list_filter = ["plans"]
|
||||||
model = User
|
model = User
|
||||||
add_form = CustomUserCreationForm
|
add_form = CustomUserCreationForm
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
*UserAdmin.fieldsets,
|
*UserAdmin.fieldsets,
|
||||||
(
|
(
|
||||||
"Stripe information",
|
"Billing information",
|
||||||
{"fields": ("stripe_id",)},
|
{"fields": ("billing_provider_id", "customer_id", "stripe_id")},
|
||||||
),
|
|
||||||
(
|
|
||||||
"Payment information",
|
|
||||||
{
|
|
||||||
"fields": (
|
|
||||||
"plans",
|
|
||||||
"last_payment",
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
# (
|
||||||
|
# "Payment information",
|
||||||
|
# {
|
||||||
|
# "fields": (
|
||||||
|
# # "plans",
|
||||||
|
# "last_payment",
|
||||||
|
# )
|
||||||
|
# },
|
||||||
|
# ),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -101,8 +99,8 @@ class AssetGroupAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
|
|
||||||
admin.site.register(User, CustomUserAdmin)
|
admin.site.register(User, CustomUserAdmin)
|
||||||
admin.site.register(Plan)
|
# admin.site.register(Plan)
|
||||||
admin.site.register(Session)
|
# admin.site.register(Session)
|
||||||
|
|
||||||
admin.site.register(Account, AccountAdmin)
|
admin.site.register(Account, AccountAdmin)
|
||||||
admin.site.register(Hook, HookAdmin)
|
admin.site.register(Hook, HookAdmin)
|
||||||
|
|||||||
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,4 +1,111 @@
|
|||||||
# from lago_python_client import Client
|
import stripe
|
||||||
# from django.conf import settings
|
from django.conf import settings
|
||||||
|
from lago_python_client import Client
|
||||||
|
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)
|
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 datetime import datetime
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from elastic_transport import ConnectionError
|
||||||
from elasticsearch import Elasticsearch
|
from elasticsearch import Elasticsearch
|
||||||
|
|
||||||
from core.util import logs
|
from core.util import logs
|
||||||
@@ -22,11 +23,16 @@ def initialise_elasticsearch():
|
|||||||
|
|
||||||
|
|
||||||
def store_msg(index, msg):
|
def store_msg(index, msg):
|
||||||
global client
|
return
|
||||||
if not client:
|
# global client
|
||||||
client = initialise_elasticsearch()
|
# if not client:
|
||||||
if "ts" not in msg:
|
# client = initialise_elasticsearch()
|
||||||
msg["ts"] = datetime.utcnow().isoformat()
|
# if "ts" not in msg:
|
||||||
result = client.index(index=index, body=msg)
|
# msg["ts"] = datetime.utcnow().isoformat()
|
||||||
if not result["result"] == "created":
|
# try:
|
||||||
log.error(f"Indexing of '{msg}' failed: {result}")
|
# 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,21 +1,21 @@
|
|||||||
from asgiref.sync import sync_to_async
|
# from asgiref.sync import sync_to_async
|
||||||
|
|
||||||
from core.models import Plan
|
# from core.models import Plan
|
||||||
|
|
||||||
|
|
||||||
async def assemble_plan_map(product_id_filter=None):
|
# async def assemble_plan_map(product_id_filter=None):
|
||||||
"""
|
# """
|
||||||
Get all the plans from the database and create an object Stripe wants.
|
# Get all the plans from the database and create an object Stripe wants.
|
||||||
"""
|
# """
|
||||||
line_items = []
|
# line_items = []
|
||||||
for plan in await sync_to_async(list)(Plan.objects.all()):
|
# for plan in await sync_to_async(list)(Plan.objects.all()):
|
||||||
if product_id_filter:
|
# if product_id_filter:
|
||||||
if plan.product_id != product_id_filter:
|
# if plan.product_id != product_id_filter:
|
||||||
continue
|
# continue
|
||||||
line_items.append(
|
# line_items.append(
|
||||||
{
|
# {
|
||||||
"price": plan.product_id,
|
# "price": plan.product_id,
|
||||||
"quantity": 1,
|
# "quantity": 1,
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
return line_items
|
# return line_items
|
||||||
|
|||||||
@@ -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 decimal import Decimal as D
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class PositionLong(BaseModel):
|
class PositionLong(BaseModel):
|
||||||
units: str
|
units: str
|
||||||
averagePrice: str | None
|
averagePrice: Optional[str] = None
|
||||||
pl: str
|
pl: str
|
||||||
resettablePL: str
|
resettablePL: str
|
||||||
financing: str
|
financing: str
|
||||||
dividendAdjustment: str
|
dividendAdjustment: str
|
||||||
guaranteedExecutionFees: str
|
guaranteedExecutionFees: str
|
||||||
tradeIDs: list[str] | None
|
tradeIDs: Optional[list[str]] = []
|
||||||
unrealizedPL: str
|
unrealizedPL: str
|
||||||
|
|
||||||
|
|
||||||
class PositionShort(BaseModel):
|
class PositionShort(BaseModel):
|
||||||
units: str
|
units: str
|
||||||
averagePrice: str | None
|
averagePrice: Optional[str] = None
|
||||||
pl: str
|
pl: str
|
||||||
resettablePL: str
|
resettablePL: str
|
||||||
financing: str
|
financing: str
|
||||||
dividendAdjustment: str
|
dividendAdjustment: str
|
||||||
guaranteedExecutionFees: str
|
guaranteedExecutionFees: str
|
||||||
tradeIDs: list[str] | None
|
tradeIDs: Optional[list[str]] = []
|
||||||
unrealizedPL: str
|
unrealizedPL: str
|
||||||
|
|
||||||
|
|
||||||
@@ -306,7 +307,7 @@ class PositionDetailsNested(BaseModel):
|
|||||||
dividendAdjustment: str
|
dividendAdjustment: str
|
||||||
guaranteedExecutionFees: str
|
guaranteedExecutionFees: str
|
||||||
unrealizedPL: str
|
unrealizedPL: str
|
||||||
marginUsed: str | None
|
marginUsed: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class PositionDetails(BaseModel):
|
class PositionDetails(BaseModel):
|
||||||
@@ -373,7 +374,9 @@ class Instrument(BaseModel):
|
|||||||
guaranteedStopLossOrderMode: str
|
guaranteedStopLossOrderMode: str
|
||||||
tags: list[InstrumentTag]
|
tags: list[InstrumentTag]
|
||||||
financing: InstrumentFinancing
|
financing: InstrumentFinancing
|
||||||
guaranteedStopLossOrderLevelRestriction: InstrumentGuaranteedRestriction | None
|
guaranteedStopLossOrderLevelRestriction: Optional[
|
||||||
|
InstrumentGuaranteedRestriction
|
||||||
|
] = None
|
||||||
|
|
||||||
|
|
||||||
class AccountInstruments(BaseModel):
|
class AccountInstruments(BaseModel):
|
||||||
@@ -474,33 +477,33 @@ class Trade(BaseModel):
|
|||||||
quoteGuaranteedExecutionFee: str
|
quoteGuaranteedExecutionFee: str
|
||||||
halfSpreadCost: str
|
halfSpreadCost: str
|
||||||
# takeProfitOrder: TakeProfitOrder | None
|
# takeProfitOrder: TakeProfitOrder | None
|
||||||
takeProfitOrder: dict | None
|
takeProfitOrder: Optional[dict] = None
|
||||||
stopLossOrder: dict | None
|
stopLossOrder: Optional[dict] = None
|
||||||
trailingStopLossOrder: dict | None
|
trailingStopLossOrder: Optional[dict] = None
|
||||||
|
|
||||||
|
|
||||||
class SideCarOrder(BaseModel):
|
class SideCarOrder(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
createTime: str
|
createTime: str
|
||||||
state: str
|
state: str
|
||||||
price: str | None
|
price: Optional[str] = None
|
||||||
timeInForce: str
|
timeInForce: str
|
||||||
gtdTime: str | None
|
gtdTime: Optional[str] = None
|
||||||
clientExtensions: dict | None
|
clientExtensions: Optional[dict] = None
|
||||||
tradeID: str
|
tradeID: str
|
||||||
clientTradeID: str | None
|
clientTradeID: Optional[str] = None
|
||||||
type: str
|
type: str
|
||||||
time: str | None
|
time: Optional[str] = None
|
||||||
priceBound: str | None
|
priceBound: Optional[str] = None
|
||||||
positionFill: str | None
|
positionFill: Optional[str] = None
|
||||||
reason: str | None
|
reason: Optional[str] = None
|
||||||
orderFillTransactionID: str | None
|
orderFillTransactionID: Optional[str] = None
|
||||||
tradeOpenedID: str | None
|
tradeOpenedID: Optional[str] = None
|
||||||
tradeReducedID: str | None
|
tradeReducedID: Optional[str] = None
|
||||||
tradeClosedIDs: list[str] | None
|
tradeClosedIDs: Optional[list[str]] = []
|
||||||
cancellingTransactionID: str | None
|
cancellingTransactionID: Optional[str] = None
|
||||||
replacesOrderID: str | None
|
replacesOrderID: Optional[str] = None
|
||||||
replacedByOrderID: str | None
|
replacedByOrderID: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class OpenTradesTrade(BaseModel):
|
class OpenTradesTrade(BaseModel):
|
||||||
@@ -517,10 +520,10 @@ class OpenTradesTrade(BaseModel):
|
|||||||
dividendAdjustment: str
|
dividendAdjustment: str
|
||||||
unrealizedPL: str
|
unrealizedPL: str
|
||||||
marginUsed: str
|
marginUsed: str
|
||||||
takeProfitOrder: SideCarOrder | None
|
takeProfitOrder: Optional[SideCarOrder] = None
|
||||||
stopLossOrder: SideCarOrder | None
|
stopLossOrder: Optional[SideCarOrder] = None
|
||||||
trailingStopLossOrder: SideCarOrder | None
|
trailingStopLossOrder: Optional[SideCarOrder] = None
|
||||||
trailingStopValue: dict | None
|
trailingStopValue: Optional[dict] = None
|
||||||
|
|
||||||
|
|
||||||
class OpenTrades(BaseModel):
|
class OpenTrades(BaseModel):
|
||||||
@@ -578,13 +581,13 @@ class OrderTransaction(BaseModel):
|
|||||||
requestID: str
|
requestID: str
|
||||||
time: str
|
time: str
|
||||||
type: str
|
type: str
|
||||||
instrument: str | None
|
instrument: Optional[str] = None
|
||||||
units: str | None
|
units: Optional[str] = None
|
||||||
timeInForce: str | None
|
timeInForce: Optional[str] = None
|
||||||
positionFill: str | None
|
positionFill: Optional[str] = None
|
||||||
reason: str
|
reason: str
|
||||||
longPositionCloseout: LongPositionCloseout | None
|
longPositionCloseout: LongPositionCloseout | None
|
||||||
longOrderFillTransaction: dict | None
|
longOrderFillTransaction: Optional[dict] = None
|
||||||
|
|
||||||
|
|
||||||
class OrderCreate(BaseModel):
|
class OrderCreate(BaseModel):
|
||||||
@@ -677,12 +680,12 @@ class TradeDetailsTrade(BaseModel):
|
|||||||
state: str
|
state: str
|
||||||
currentUnits: str
|
currentUnits: str
|
||||||
realizedPL: str
|
realizedPL: str
|
||||||
closingTransactionIDs: list[str] | None
|
closingTransactionIDs: Optional[list[str]] = []
|
||||||
financing: str
|
financing: str
|
||||||
dividendAdjustment: str
|
dividendAdjustment: str
|
||||||
closeTime: str | None
|
closeTime: Optional[str] = None
|
||||||
averageClosePrice: str | None
|
averageClosePrice: Optional[str] = None
|
||||||
clientExtensions: ClientExtensions | None
|
clientExtensions: Optional[ClientExtensions] = None
|
||||||
|
|
||||||
|
|
||||||
class TradeDetails(BaseModel):
|
class TradeDetails(BaseModel):
|
||||||
@@ -733,10 +736,10 @@ TradeCloseSchema = {
|
|||||||
|
|
||||||
|
|
||||||
class TradeCRCDO(BaseModel):
|
class TradeCRCDO(BaseModel):
|
||||||
takeProfitOrderCancelTransaction: OrderTransaction
|
takeProfitOrderCancelTransaction: Optional[OrderTransaction]
|
||||||
takeProfitOrderTransaction: OrderTransaction
|
takeProfitOrderTransaction: Optional[OrderTransaction]
|
||||||
stopLossOrderCancelTransaction: OrderTransaction
|
stopLossOrderCancelTransaction: Optional[OrderTransaction]
|
||||||
stopLossOrderTransaction: OrderTransaction
|
stopLossOrderTransaction: Optional[OrderTransaction]
|
||||||
relatedTransactionIDs: list[str]
|
relatedTransactionIDs: list[str]
|
||||||
lastTransactionID: str
|
lastTransactionID: str
|
||||||
|
|
||||||
|
|||||||
@@ -38,11 +38,15 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
log.debug(f"Scheduling checking process job every {INTERVAL} seconds")
|
log.debug(f"Scheduling checking process job every {INTERVAL} seconds")
|
||||||
scheduler.add_job(job, "interval", seconds=INTERVAL)
|
scheduler.add_job(job, "interval", seconds=INTERVAL)
|
||||||
|
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
scheduler._eventloop = loop
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
try:
|
try:
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
except (KeyboardInterrupt, SystemExit):
|
except (KeyboardInterrupt, SystemExit):
|
||||||
log.info("Process terminating")
|
log.info("Process terminating")
|
||||||
finally:
|
finally:
|
||||||
|
scheduler.shutdown(wait=False)
|
||||||
loop.close()
|
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_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')),
|
('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')),
|
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||||
('stripe_id', models.CharField(blank=True, max_length=255, null=True)),
|
('billing_provider_id', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
('last_payment', models.DateTimeField(blank=True, null=True)),
|
|
||||||
('email', models.EmailField(max_length=254, unique=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')),
|
('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()),
|
('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(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name='user',
|
||||||
name='user_permissions',
|
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
|
from django.db import migrations, models
|
||||||
|
|
||||||
@@ -6,13 +6,13 @@ from django.db import migrations, models
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0001_initial'),
|
('core', '0003_user_customer_id'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='session',
|
model_name='user',
|
||||||
name='session',
|
name='stripe_id',
|
||||||
field=models.CharField(blank=True, max_length=255, null=True),
|
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
|
import uuid
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
# import stripe
|
import stripe
|
||||||
# from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from core.exchanges.alpaca import AlpacaExchange
|
from core.exchanges.alpaca import AlpacaExchange
|
||||||
from core.exchanges.fake import FakeExchange
|
from core.exchanges.fake import FakeExchange
|
||||||
|
from core.exchanges.mexc import MEXCExchange
|
||||||
from core.exchanges.oanda import OANDAExchange
|
from core.exchanges.oanda import OANDAExchange
|
||||||
|
|
||||||
# from core.lib.customers import get_or_create, update_customer_fields
|
# from core.lib.customers import get_or_create, update_customer_fields
|
||||||
|
from core.lib import billing
|
||||||
from core.util import logs
|
from core.util import logs
|
||||||
|
|
||||||
log = logs.get_logger(__name__)
|
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 = (
|
TYPE_CHOICES = (
|
||||||
("market", "Market"),
|
("market", "Market"),
|
||||||
("limit", "Limit"),
|
("limit", "Limit"),
|
||||||
@@ -79,6 +86,14 @@ ADJUST_CLOSE_NOTIFY_CHOICES = (
|
|||||||
("adjust", "Adjust violating trades"),
|
("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):
|
# class Plan(models.Model):
|
||||||
# name = models.CharField(max_length=255, unique=True)
|
# name = models.CharField(max_length=255, unique=True)
|
||||||
@@ -93,21 +108,38 @@ ADJUST_CLOSE_NOTIFY_CHOICES = (
|
|||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
# Stripe customer ID
|
# Stripe customer ID
|
||||||
# unique_id = models.UUIDField(
|
stripe_id = models.CharField(max_length=255, null=True, blank=True)
|
||||||
# default=uuid.uuid4,
|
customer_id = models.UUIDField(default=uuid.uuid4, null=True, blank=True)
|
||||||
# )
|
|
||||||
# stripe_id = models.CharField(max_length=255, null=True, blank=True)
|
|
||||||
billing_provider_id = models.CharField(max_length=255, null=True, blank=True)
|
billing_provider_id = models.CharField(max_length=255, null=True, blank=True)
|
||||||
# last_payment = models.DateTimeField(null=True, blank=True)
|
# last_payment = models.DateTimeField(null=True, blank=True)
|
||||||
# plans = models.ManyToManyField(Plan, blank=True)
|
# plans = models.ManyToManyField(Plan, blank=True)
|
||||||
email = models.EmailField(unique=True)
|
email = models.EmailField(unique=True)
|
||||||
|
|
||||||
# def __init__(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
# super().__init__(*args, **kwargs)
|
if settings.BILLING_ENABLED:
|
||||||
# self._original = self
|
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
|
# Override save to update attributes in Lago
|
||||||
def save(self, *args, **kwargs):
|
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)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def get_notification_settings(self):
|
def get_notification_settings(self):
|
||||||
@@ -115,7 +147,12 @@ class User(AbstractUser):
|
|||||||
|
|
||||||
|
|
||||||
class Account(models.Model):
|
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)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
exchange = models.CharField(choices=EXCHANGE_CHOICES, max_length=255)
|
exchange = models.CharField(choices=EXCHANGE_CHOICES, max_length=255)
|
||||||
@@ -139,10 +176,12 @@ class Account(models.Model):
|
|||||||
if client:
|
if client:
|
||||||
response = client.get_instruments()
|
response = client.get_instruments()
|
||||||
supported_symbols = client.get_supported_assets(response)
|
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}")
|
log.debug(f"Supported symbols for {self.name}: {supported_symbols}")
|
||||||
self.supported_symbols = supported_symbols
|
self.supported_symbols = supported_symbols
|
||||||
self.instruments = response
|
self.instruments = response
|
||||||
|
if "currency" in acct_info.keys():
|
||||||
|
currency = acct_info["currency"]
|
||||||
self.currency = currency
|
self.currency = currency
|
||||||
if save:
|
if save:
|
||||||
self.save()
|
self.save()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load has_plan %}
|
|
||||||
{% load cache %}
|
{% load cache %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -287,7 +286,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if settings.STRIPE_ENABLED %}
|
{% if settings.BILLING_ENABLED %}
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<a class="navbar-item" href="{% url 'billing' %}">
|
<a class="navbar-item" href="{% url 'billing' %}">
|
||||||
Billing
|
Billing
|
||||||
@@ -312,7 +311,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% 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 %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,20 +10,6 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="tag">{{ user.first_name }} {{ user.last_name }}</span>
|
<span class="tag">{{ user.first_name }} {{ user.last_name }}</span>
|
||||||
</a>
|
</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' %}">
|
<a class="panel-block" href="{% url 'portal' %}">
|
||||||
<span class="panel-icon">
|
<span class="panel-icon">
|
||||||
<i class="fa-brands fa-stripe-s" aria-hidden="true"></i>
|
<i class="fa-brands fa-stripe-s" aria-hidden="true"></i>
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
from django import template
|
|
||||||
|
|
||||||
register = template.Library()
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def has_plan(user, plan_name):
|
|
||||||
if not hasattr(user, "plans"):
|
|
||||||
return False
|
|
||||||
plan_list = [plan.name for plan in user.plans.all()]
|
|
||||||
return plan_name in plan_list
|
|
||||||
@@ -5,6 +5,15 @@ from django.test import TestCase
|
|||||||
from core.models import TradingTime, User
|
from core.models import TradingTime, User
|
||||||
|
|
||||||
|
|
||||||
|
class ModelTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
# Create a test user
|
||||||
|
self.user = User.objects.create_user(
|
||||||
|
username="testuser",
|
||||||
|
email="testuser@example.com",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MarketTestCase(TestCase):
|
class MarketTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Create a test user
|
# Create a test user
|
||||||
|
|||||||
@@ -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):
|
def test_protection_violated(self):
|
||||||
self.trades[0]["takeProfitOrder"] = {"price": "0.0001"}
|
self.trades[0]["takeProfitOrder"] = {"price": "0.0001"}
|
||||||
self.trades[0]["stopLossOrder"] = {"price": "0.0001"}
|
self.trades[0]["stopLossOrder"] = {"price": "0.0001"}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user