From baa8e4feadac6b816624d38ec606a7bd417dd2ef Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Fri, 25 Nov 2022 18:01:34 +0000 Subject: [PATCH] Implement configuration of trading times --- app/urls.py | 31 +++++++++- core/forms.py | 15 ++++- core/migrations/0028_tradingtime.py | 26 ++++++++ .../migrations/0029_alter_tradingtime_name.py | 19 ++++++ ...0030_remove_tradingtime_end_ts_and_more.py | 45 ++++++++++++++ core/models.py | 19 ++++++ core/templates/base.html | 14 +++++ .../templates/partials/trading-time-list.html | 61 +++++++++++++++++++ core/views/limits.py | 47 ++++++++++++++ 9 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 core/migrations/0028_tradingtime.py create mode 100644 core/migrations/0029_alter_tradingtime_name.py create mode 100644 core/migrations/0030_remove_tradingtime_end_ts_and_more.py create mode 100644 core/templates/partials/trading-time-list.html create mode 100644 core/views/limits.py diff --git a/app/urls.py b/app/urls.py index 8f6f211..518a0dc 100644 --- a/app/urls.py +++ b/app/urls.py @@ -21,7 +21,16 @@ from django.urls import include, path from django.views.generic import TemplateView from django_otp.forms import OTPAuthenticationForm -from core.views import accounts, base, callbacks, hooks, positions, strategies, trades +from core.views import ( + accounts, + base, + callbacks, + hooks, + limits, + positions, + strategies, + trades, +) from core.views.stripe_callbacks import Callback urlpatterns = [ @@ -136,4 +145,24 @@ urlpatterns = [ strategies.StrategyDelete.as_view(), name="strategy_delete", ), + path( + "trading_times//", + limits.TradingTimeList.as_view(), + name="tradingtimes", + ), + path( + "trading_times//create/", + limits.TradingTimeCreate.as_view(), + name="tradingtime_create", + ), + path( + "trading_times//update//", + limits.TradingTimeUpdate.as_view(), + name="tradingtime_update", + ), + path( + "trading_times//delete//", + limits.TradingTimeDelete.as_view(), + name="tradingtime_delete", + ), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/core/forms.py b/core/forms.py index 9316c78..570e8b6 100644 --- a/core/forms.py +++ b/core/forms.py @@ -2,7 +2,7 @@ from django import forms from django.contrib.auth.forms import UserCreationForm from django.forms import ModelForm -from .models import Account, Hook, Strategy, Trade, User +from .models import Account, Hook, Strategy, Trade, TradingTime, User # Create your forms here. @@ -96,3 +96,16 @@ class TradeForm(ModelForm): "take_profit", "direction", ) + + +class TradingTimeForm(ModelForm): + class Meta: + model = TradingTime + fields = ( + "name", + "description", + "start_day", + "start_time", + "end_day", + "end_time", + ) diff --git a/core/migrations/0028_tradingtime.py b/core/migrations/0028_tradingtime.py new file mode 100644 index 0000000..5967675 --- /dev/null +++ b/core/migrations/0028_tradingtime.py @@ -0,0 +1,26 @@ +# 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)), + ], + ), + ] diff --git a/core/migrations/0029_alter_tradingtime_name.py b/core/migrations/0029_alter_tradingtime_name.py new file mode 100644 index 0000000..462baab --- /dev/null +++ b/core/migrations/0029_alter_tradingtime_name.py @@ -0,0 +1,19 @@ +# 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, + ), + ] diff --git a/core/migrations/0030_remove_tradingtime_end_ts_and_more.py b/core/migrations/0030_remove_tradingtime_end_ts_and_more.py new file mode 100644 index 0000000..7803dc0 --- /dev/null +++ b/core/migrations/0030_remove_tradingtime_end_ts_and_more.py @@ -0,0 +1,45 @@ +# 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, + ), + ] diff --git a/core/models.py b/core/models.py index c110993..5802a14 100644 --- a/core/models.py +++ b/core/models.py @@ -24,6 +24,15 @@ TIF_CHOICES = ( ("fok", "FOK (Fill Or Kill)"), ("ioc", "IOC (Immediate Or Cancel)"), ) +DAY_CHOICES = ( + ("monday", "Monday"), + ("tuesday", "Tuesday"), + ("wednesday", "Wednesday"), + ("thursday", "Thursday"), + ("friday", "Friday"), + ("saturday", "Saturday"), + ("sunday", "Sunday"), +) class Plan(models.Model): @@ -237,6 +246,16 @@ class Strategy(models.Model): return self.name +class TradingTime(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + name = models.CharField(max_length=255) + description = models.TextField(null=True, blank=True) + start_day = models.CharField(choices=DAY_CHOICES, max_length=255) + end_day = models.CharField(choices=DAY_CHOICES, max_length=255) + start_time = models.TimeField() + end_time = models.TimeField() + + # class Perms(models.Model): # class Meta: # permissions = ( diff --git a/core/templates/base.html b/core/templates/base.html index b94a596..818e50d 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -234,6 +234,20 @@ + {% endif %} {% if settings.STRIPE_ENABLED %} {% if user.is_authenticated %} diff --git a/core/templates/partials/trading-time-list.html b/core/templates/partials/trading-time-list.html new file mode 100644 index 0000000..761f208 --- /dev/null +++ b/core/templates/partials/trading-time-list.html @@ -0,0 +1,61 @@ +{% include 'partials/notify.html' %} + + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + + {% endfor %} + +
idusernamedescriptionstartendactions
{{ item.id }}{{ item.user }}{{ item.name }}{{ item.description }}{{ item.start_day }} at {{ item.start_time }}{{ item.end_day }} at {{ item.end_time }} +
+ + +
+
diff --git a/core/views/limits.py b/core/views/limits.py new file mode 100644 index 0000000..a23bb8f --- /dev/null +++ b/core/views/limits.py @@ -0,0 +1,47 @@ +from django.contrib.auth.mixins import LoginRequiredMixin + +from core.forms import TradingTimeForm +from core.models import TradingTime +from core.util import logs +from core.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate + +log = logs.get_logger(__name__) + + +class TradingTimeList(LoginRequiredMixin, ObjectList): + list_template = "partials/trading-time-list.html" + model = TradingTime + page_title = "List of allowed trading times. Used as options for a strategy." + page_subtitle = "Add times here in order to permit trading." + + list_url_name = "tradingtimes" + list_url_args = ["type"] + + submit_url_name = "tradingtime_create" + + +class TradingTimeCreate(LoginRequiredMixin, ObjectCreate): + model = TradingTime + form_class = TradingTimeForm + + list_url_name = "tradingtimes" + list_url_args = ["type"] + + submit_url_name = "tradingtime_create" + + +class TradingTimeUpdate(LoginRequiredMixin, ObjectUpdate): + model = TradingTime + form_class = TradingTimeForm + + list_url_name = "tradingtimes" + list_url_args = ["type"] + + submit_url_name = "tradingtime_update" + + +class TradingTimeDelete(LoginRequiredMixin, ObjectDelete): + model = TradingTime + + list_url_name = "tradingtimes" + list_url_args = ["type"]