diff --git a/app/urls.py b/app/urls.py index a8bc8a4..a93678b 100644 --- a/app/urls.py +++ b/app/urls.py @@ -29,6 +29,7 @@ from core.views import ( hooks, limits, notifications, + ordersettings, positions, profit, risk, @@ -284,4 +285,25 @@ urlpatterns = [ assets.AssetRuleDelete.as_view(), name="assetrule_delete", ), + # Order Settings + path( + "ordersettings//", + ordersettings.OrderSettingsList.as_view(), + name="ordersettings", + ), + path( + "ordersettings//create/", + ordersettings.OrderSettingsCreate.as_view(), + name="ordersettings_create", + ), + path( + "ordersettings//update//", + ordersettings.OrderSettingsUpdate.as_view(), + name="ordersettings_update", + ), + path( + "ordersettings//delete//", + ordersettings.OrderSettingsDelete.as_view(), + name="ordersettings_delete", + ), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/core/forms.py b/core/forms.py index accd5e6..e22ed51 100644 --- a/core/forms.py +++ b/core/forms.py @@ -10,6 +10,7 @@ from .models import ( # AssetRestriction, AssetRule, Hook, NotificationSettings, + OrderSettings, RiskModel, Signal, Strategy, @@ -125,16 +126,17 @@ class StrategyForm(RestrictedFormMixin, ModelForm): "asset_group", "risk_model", "trading_times", - "order_type", - "time_in_force", + "order_settings", + # "order_type", + # "time_in_force", "entry_signals", "exit_signals", "trend_signals", "enabled", - "take_profit_percent", - "stop_loss_percent", - "trailing_stop_loss_percent", - "trade_size_percent", + # "take_profit_percent", + # "stop_loss_percent", + # "trailing_stop_loss_percent", + # "trade_size_percent", ) help_texts = { @@ -144,16 +146,16 @@ class StrategyForm(RestrictedFormMixin, ModelForm): "asset_group": "Asset groups determine which pairs can be traded.", "risk_model": "The risk model to use for this strategy. Highly recommended.", "trading_times": "When the strategy will place new trades.", - "order_type": "Market: Buy/Sell at the current market price. Limit: Buy/Sell at a specified price. Limits protect you more against market slippage.", - "time_in_force": "The time in force controls how the order is executed.", + # "order_type": "Market: Buy/Sell at the current market price. Limit: Buy/Sell at a specified price. Limits protect you more against market slippage.", + # "time_in_force": "The time in force controls how the order is executed.", "entry_signals": "Callbacks received to these signals will trigger a trade.", "exit_signals": "Callbacks received to these signals will close all trades for the symbol on the account.", "trend_signals": "Callbacks received to these signals will limit the trading direction of the given symbol to the callback direction until further notice.", "enabled": "Whether the strategy is enabled.", - "take_profit_percent": "The take profit will be set at this percentage above/below the entry price.", - "stop_loss_percent": "The stop loss will be set at this percentage above/below the entry price.", - "trailing_stop_loss_percent": "The trailing stop loss will be set at this percentage above/below the entry price. A trailing stop loss will follow the price as it moves in your favor.", - "trade_size_percent": "Percentage of the account balance to use for each trade.", + # "take_profit_percent": "The take profit will be set at this percentage above/below the entry price.", + # "stop_loss_percent": "The stop loss will be set at this percentage above/below the entry price.", + # "trailing_stop_loss_percent": "The trailing stop loss will be set at this percentage above/below the entry price. A trailing stop loss will follow the price as it moves in your favor.", + # "trade_size_percent": "Percentage of the account balance to use for each trade.", } entry_signals = forms.ModelMultipleChoiceField( @@ -361,3 +363,28 @@ class AssetRuleForm(RestrictedFormMixin, ModelForm): "trigger_below": "Trigger Bearish when value is below this.", "trigger_above": "Trigger Bullish when value is above this.", } + + +class OrderSettingsForm(RestrictedFormMixin, ModelForm): + class Meta: + model = OrderSettings + fields = ( + "name", + "description", + "order_type", + "time_in_force", + "take_profit_percent", + "stop_loss_percent", + "trailing_stop_loss_percent", + "trade_size_percent", + ) + help_texts = { + "name": "Name of the order settings. Informational only.", + "description": "Description of the order settings. Informational only.", + "order_type": "Market: Buy/Sell at the current market price. Limit: Buy/Sell at a specified price. Limits protect you more against market slippage.", + "time_in_force": "The time in force controls how the order is executed.", + "take_profit_percent": "The take profit will be set at this percentage above/below the entry price.", + "stop_loss_percent": "The stop loss will be set at this percentage above/below the entry price.", + "trailing_stop_loss_percent": "The trailing stop loss will be set at this percentage above/below the entry price. A trailing stop loss will follow the price as it moves in your favor.", + "trade_size_percent": "Percentage of the account balance to use for each trade.", + } diff --git a/core/migrations/0066_remove_account_risk_model_and_more.py b/core/migrations/0066_remove_account_risk_model_and_more.py index cde5d97..5f98019 100644 --- a/core/migrations/0066_remove_account_risk_model_and_more.py +++ b/core/migrations/0066_remove_account_risk_model_and_more.py @@ -1,7 +1,7 @@ # Generated by Django 4.1.6 on 2023-02-15 18:11 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/core/migrations/0067_ordersettings_strategy_order_settings.py b/core/migrations/0067_ordersettings_strategy_order_settings.py new file mode 100644 index 0000000..1a2e176 --- /dev/null +++ b/core/migrations/0067_ordersettings_strategy_order_settings.py @@ -0,0 +1,30 @@ +# 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)), + ], + ), + ] diff --git a/core/models.py b/core/models.py index a2bc74c..32b5ace 100644 --- a/core/models.py +++ b/core/models.py @@ -397,6 +397,9 @@ class Strategy(models.Model): risk_model = models.ForeignKey( "core.RiskModel", on_delete=models.PROTECT, null=True, blank=True ) + order_settings = models.ForeignKey( + "core.OrderSettings", on_delete=models.PROTECT, null=True, blank=True + ) class Meta: verbose_name_plural = "strategies" @@ -481,3 +484,17 @@ class AssetRule(models.Model): # Ensure that the asset is unique per group class Meta: unique_together = ("asset", "group") + + +class OrderSettings(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + name = models.CharField(max_length=255) + description = models.TextField(null=True, blank=True) + order_type = models.CharField( + choices=TYPE_CHOICES, max_length=255, default="market" + ) + time_in_force = models.CharField(choices=TIF_CHOICES, max_length=255, default="gtc") + take_profit_percent = models.FloatField(default=1.5) + stop_loss_percent = models.FloatField(default=1.0) + trailing_stop_loss_percent = models.FloatField(default=1.0, null=True, blank=True) + trade_size_percent = models.FloatField(default=0.5) diff --git a/core/templates/base.html b/core/templates/base.html index 8a24a0e..1727959 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -248,6 +248,9 @@ Strategies + + Order Settings + Signals diff --git a/core/templates/partials/assetgroup-list.html b/core/templates/partials/assetgroup-list.html index 233ca24..4abeea3 100644 --- a/core/templates/partials/assetgroup-list.html +++ b/core/templates/partials/assetgroup-list.html @@ -24,7 +24,7 @@ {{ item.id }} {{ item.user }} {{ item.name }} - {{ item.description }} + {{ item.description|truncatechars:80 }} diff --git a/core/templates/partials/ordersettings-list.html b/core/templates/partials/ordersettings-list.html new file mode 100644 index 0000000..7892b99 --- /dev/null +++ b/core/templates/partials/ordersettings-list.html @@ -0,0 +1,69 @@ +{% load cache %} +{% load cachalot cache %} +{% get_last_invalidation 'core.OrderSettings' as last %} +{% include 'mixins/partials/notify.html' %} +{% cache 600 objects_ordersettings request.user.id object_list type last %} + + + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + + + + {% endfor %} + +
idusernamedescriptionTPSLTSLsizeactions
{{ item.id }}{{ item.user }}{{ item.name }}{{ item.description|truncatechars:80 }}{{ item.take_profit_percent}}{{ item.stop_loss_percent }}{{ item.trailing_stop_loss_percent }}{{ item.trade_size_percent }} +
+ + +
+
+{% endcache %} \ No newline at end of file diff --git a/core/templates/partials/strategy-list.html b/core/templates/partials/strategy-list.html index 3a6ceac..9118f49 100644 --- a/core/templates/partials/strategy-list.html +++ b/core/templates/partials/strategy-list.html @@ -16,8 +16,6 @@ description account enabled - TP - SL actions {% for item in object_list %} @@ -37,8 +35,6 @@ {% endif %} - {{ item.take_profit_percent }} - {{ item.stop_loss_percent }}