Compare commits

...

4 Commits

7 changed files with 80 additions and 8 deletions

View File

@ -165,6 +165,47 @@ class StrategyForm(RestrictedFormMixin, ModelForm):
queryset=TradingTime.objects.all(), widget=forms.CheckboxSelectMultiple queryset=TradingTime.objects.all(), widget=forms.CheckboxSelectMultiple
) )
def clean(self):
super(StrategyForm, self).clean()
entry_signals = self.cleaned_data.get("entry_signals")
exit_signals = self.cleaned_data.get("exit_signals")
for entry in entry_signals.all():
if entry in exit_signals.all():
self._errors["entry_signals"] = self.error_class(
[
"You cannot bet against yourself. Do not use the same signal for entry and exit."
]
)
for exit in exit_signals.all():
if exit in entry_signals.all():
self._errors["exit_signals"] = self.error_class(
[
"You cannot bet against yourself. Do not use the same signal for entry and exit."
]
)
# Get all the directions for entry and exit signals
entries_set = set([x.direction for x in entry_signals.all()])
exits_set = set([x.direction for x in exit_signals.all()])
# Make sure both fields are filled before we check this
if entries_set and exits_set:
# Combine them into one set
check_set = set()
check_set.update(entries_set, exits_set)
# If the length is 1, they are all the same direction
if len(check_set) == 1:
self._errors["entry_signals"] = self.error_class(
[
"You cannot have entry and exit signals that are the same direction. At least one must be opposing."
]
)
self._errors["exit_signals"] = self.error_class(
[
"You cannot have entry and exit signals that are the same direction. At least one must be opposing."
]
)
class TradeForm(RestrictedFormMixin, ModelForm): class TradeForm(RestrictedFormMixin, ModelForm):
class Meta: class Meta:

View File

@ -295,9 +295,10 @@ def execute_strategy(callback, strategy):
user = strategy.user user = strategy.user
account = strategy.account account = strategy.account
hook = callback.hook hook = callback.hook
signal = callback.signal
base = callback.base base = callback.base
quote = callback.quote quote = callback.quote
direction = hook.direction direction = signal.direction
# Don't be silly # Don't be silly
if callback.exchange != account.exchange: if callback.exchange != account.exchange:
@ -359,6 +360,7 @@ def execute_strategy(callback, strategy):
user=user, user=user,
account=account, account=account,
hook=hook, hook=hook,
signal=signal,
symbol=symbol, symbol=symbol,
type=type, type=type,
time_in_force=strategy.time_in_force, time_in_force=strategy.time_in_force,
@ -381,8 +383,22 @@ def execute_strategy(callback, strategy):
def process_callback(callback): def process_callback(callback):
log.info(f"Received callback for {callback.hook}") log.info(f"Received callback for {callback.hook} - {callback.signal}")
strategies = Strategy.objects.filter(hooks=callback.hook, enabled=True)
# Scan for entry
log.debug("Scanning for entry strategies...")
strategies = Strategy.objects.filter(entry_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)
# Scan for exit
log.debug("Scanning for entry strategies...")
strategies = Strategy.objects.filter(exit_signals=callback.signal, enabled=True)
log.debug(f"Matched strategies: {strategies}") log.debug(f"Matched strategies: {strategies}")
for strategy in strategies: for strategy in strategies:
log.debug(f"Executing strategy {strategy}") log.debug(f"Executing strategy {strategy}")

View File

@ -1,8 +1,8 @@
# Generated by Django 4.1.3 on 2022-12-01 18:22 # Generated by Django 4.1.3 on 2022-12-01 18:22
import django.db.models.deletion
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -1,7 +1,7 @@
# Generated by Django 4.1.3 on 2022-12-01 18:33 # Generated by Django 4.1.3 on 2022-12-01 18:33
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -1,7 +1,7 @@
# Generated by Django 4.1.3 on 2022-12-01 18:40 # Generated by Django 4.1.3 on 2022-12-01 18:40
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@ -10,7 +10,7 @@ from rest_framework.views import APIView
from core.forms import HookForm from core.forms import HookForm
from core.lib import market from core.lib import market
from core.lib.schemas.drakdoo_s import DrakdooCallback from core.lib.schemas.drakdoo_s import DrakdooCallback
from core.models import Callback, Hook from core.models import Callback, Hook, Signal
from core.util import logs from core.util import logs
from core.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate from core.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
@ -88,16 +88,29 @@ class HookAPI(APIView):
except Hook.DoesNotExist: except Hook.DoesNotExist:
return HttpResponseBadRequest("Hook does not exist.") return HttpResponseBadRequest("Hook does not exist.")
# Try getting the signal
try:
signal = Signal.objects.get(signal=hook_resp.title)
except Signal.DoesNotExist:
return HttpResponseBadRequest("Signal does not exist.")
# For uptime checks/testing
if data["exchange"].lower() == "n/a": if data["exchange"].lower() == "n/a":
log.debug("HookAPI callback: exchange is N/A, skipping") log.debug("HookAPI callback: exchange is N/A, skipping")
return HttpResponse("OK") return HttpResponse("OK")
# Set the signal relation
data["signal"] = signal
# Create the callback object # Create the callback object
callback = Callback.objects.create(hook=hook, **data) callback = Callback.objects.create(hook=hook, **data)
callback.save() callback.save()
market.process_callback(callback) market.process_callback(callback)
# Bump received count # Bump received count
hook.received = hook.received + 1 hook.received = hook.received + 1
signal.received = signal.received + 1
hook.save() hook.save()
signal.save()
return HttpResponse("OK") return HttpResponse("OK")

View File

@ -12,7 +12,9 @@ class SignalList(LoginRequiredMixin, ObjectList):
list_template = "partials/signal-list.html" list_template = "partials/signal-list.html"
model = Signal model = Signal
page_title = "List of signals. Linked to hooks and strategies." page_title = "List of signals. Linked to hooks and strategies."
page_subtitle = "Link signals you have defined in Drakdoo to their corresponding hooks." page_subtitle = (
"Link signals you have defined in Drakdoo to their corresponding hooks."
)
list_url_name = "signals" list_url_name = "signals"
list_url_args = ["type"] list_url_args = ["type"]