Implement trend signals
This commit is contained in:
parent
242c9fbaed
commit
3b3faecdf1
|
@ -122,6 +122,7 @@ class StrategyForm(RestrictedFormMixin, ModelForm):
|
||||||
"time_in_force",
|
"time_in_force",
|
||||||
"entry_signals",
|
"entry_signals",
|
||||||
"exit_signals",
|
"exit_signals",
|
||||||
|
"trend_signals",
|
||||||
"enabled",
|
"enabled",
|
||||||
"take_profit_percent",
|
"take_profit_percent",
|
||||||
"stop_loss_percent",
|
"stop_loss_percent",
|
||||||
|
@ -138,8 +139,9 @@ class StrategyForm(RestrictedFormMixin, ModelForm):
|
||||||
"trading_times": "When the strategy will place new trades.",
|
"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.",
|
"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.",
|
"time_in_force": "The time in force controls how the order is executed.",
|
||||||
"entry_signals": "The entry signals to attach to this strategy. Callbacks received to these signals will trigger a trade.",
|
"entry_signals": "Callbacks received to these signals will trigger a trade.",
|
||||||
"exit_signals": "The exit signals to attach to this strategy. Callbacks received to these signals will close all trades for the symbol on the account.",
|
"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.",
|
"enabled": "Whether the strategy is enabled.",
|
||||||
"take_profit_percent": "The take profit will be set at this percentage above/below the entry price.",
|
"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.",
|
"stop_loss_percent": "The stop loss will be set at this percentage above/below the entry price.",
|
||||||
|
@ -161,6 +163,12 @@ class StrategyForm(RestrictedFormMixin, ModelForm):
|
||||||
help_text=Meta.help_texts["exit_signals"],
|
help_text=Meta.help_texts["exit_signals"],
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
trend_signals = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Signal.objects.all(),
|
||||||
|
widget=forms.CheckboxSelectMultiple,
|
||||||
|
help_text=Meta.help_texts["trend_signals"],
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
trading_times = forms.ModelMultipleChoiceField(
|
trading_times = forms.ModelMultipleChoiceField(
|
||||||
queryset=TradingTime.objects.all(), widget=forms.CheckboxSelectMultiple
|
queryset=TradingTime.objects.all(), widget=forms.CheckboxSelectMultiple
|
||||||
)
|
)
|
||||||
|
|
|
@ -296,7 +296,7 @@ def execute_strategy(callback, strategy, func):
|
||||||
:param strategy: Strategy object
|
:param strategy: Strategy object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Only check times for entries. We can always exit trades.
|
# Only check times for entries. We can always exit trades and set trends.
|
||||||
if func == "entry":
|
if func == "entry":
|
||||||
# Check if we can trade now!
|
# Check if we can trade now!
|
||||||
now_utc = datetime.utcnow()
|
now_utc = datetime.utcnow()
|
||||||
|
@ -380,6 +380,31 @@ def execute_strategy(callback, strategy, func):
|
||||||
response = account.client.close_position(side, symbol)
|
response = account.client.close_position(side, symbol)
|
||||||
log.debug(f"Close position response: {response}")
|
log.debug(f"Close position response: {response}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Set the trend
|
||||||
|
elif func == "trend":
|
||||||
|
if strategy.trends is None:
|
||||||
|
strategy.trends = {}
|
||||||
|
strategy.trends[symbol] = direction
|
||||||
|
strategy.save()
|
||||||
|
log.debug(f"Set trend for {symbol}: {direction}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if we are trading against the trend
|
||||||
|
if strategy.trend_signals is not None:
|
||||||
|
if strategy.trends is None:
|
||||||
|
log.debug("Refusing to trade with no trend signals received")
|
||||||
|
return
|
||||||
|
if symbol not in strategy.trends:
|
||||||
|
log.debug("Refusing to trade asset without established trend")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if strategy.trends[symbol] != direction:
|
||||||
|
log.debug("Refusing to trade against the trend")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
log.debug(f"Trend check passed for {symbol} - {direction}")
|
||||||
|
|
||||||
type = strategy.order_type
|
type = strategy.order_type
|
||||||
|
|
||||||
# Get the account's balance in the native account currency
|
# Get the account's balance in the native account currency
|
||||||
|
@ -443,6 +468,17 @@ def execute_strategy(callback, strategy, func):
|
||||||
def process_callback(callback):
|
def process_callback(callback):
|
||||||
log.info(f"Received callback for {callback.hook} - {callback.signal}")
|
log.info(f"Received callback for {callback.hook} - {callback.signal}")
|
||||||
|
|
||||||
|
# Scan for trend
|
||||||
|
log.debug("Scanning for trend strategies...")
|
||||||
|
strategies = Strategy.objects.filter(trend_signals=callback.signal, enabled=True)
|
||||||
|
log.debug(f"Matched strategies: {strategies}")
|
||||||
|
for strategy in strategies:
|
||||||
|
log.debug(f"Executing strategy {strategy}")
|
||||||
|
if callback.hook.user != strategy.user:
|
||||||
|
log.error("Ownership differs between callback and strategy.")
|
||||||
|
continue
|
||||||
|
execute_strategy(callback, strategy, func="trend")
|
||||||
|
|
||||||
# Scan for entry
|
# Scan for entry
|
||||||
log.debug("Scanning for entry strategies...")
|
log.debug("Scanning for entry strategies...")
|
||||||
strategies = Strategy.objects.filter(entry_signals=callback.signal, enabled=True)
|
strategies = Strategy.objects.filter(entry_signals=callback.signal, enabled=True)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# 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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -334,6 +334,9 @@ class Strategy(models.Model):
|
||||||
exit_signals = models.ManyToManyField(
|
exit_signals = models.ManyToManyField(
|
||||||
Signal, related_name="exit_strategies", blank=True
|
Signal, related_name="exit_strategies", blank=True
|
||||||
)
|
)
|
||||||
|
trend_signals = models.ManyToManyField(
|
||||||
|
Signal, related_name="trend_strategies", blank=True
|
||||||
|
)
|
||||||
enabled = models.BooleanField(default=False)
|
enabled = models.BooleanField(default=False)
|
||||||
take_profit_percent = models.FloatField(default=1.5)
|
take_profit_percent = models.FloatField(default=1.5)
|
||||||
stop_loss_percent = models.FloatField(default=1.0)
|
stop_loss_percent = models.FloatField(default=1.0)
|
||||||
|
@ -341,6 +344,7 @@ class Strategy(models.Model):
|
||||||
price_slippage_percent = models.FloatField(default=2.5)
|
price_slippage_percent = models.FloatField(default=2.5)
|
||||||
callback_price_deviation_percent = models.FloatField(default=0.5)
|
callback_price_deviation_percent = models.FloatField(default=0.5)
|
||||||
trade_size_percent = models.FloatField(default=0.5)
|
trade_size_percent = models.FloatField(default=0.5)
|
||||||
|
trends = models.JSONField(null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name_plural = "strategies"
|
verbose_name_plural = "strategies"
|
||||||
|
|
Loading…
Reference in New Issue