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
)
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 Meta:

View File

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

View File

@ -1,8 +1,8 @@
# 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
import django.db.models.deletion
class Migration(migrations.Migration):

View File

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

View File

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

View File

@ -10,7 +10,7 @@ from rest_framework.views import APIView
from core.forms import HookForm
from core.lib import market
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.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
@ -88,16 +88,29 @@ class HookAPI(APIView):
except Hook.DoesNotExist:
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":
log.debug("HookAPI callback: exchange is N/A, skipping")
return HttpResponse("OK")
# Set the signal relation
data["signal"] = signal
# Create the callback object
callback = Callback.objects.create(hook=hook, **data)
callback.save()
market.process_callback(callback)
# Bump received count
hook.received = hook.received + 1
signal.received = signal.received + 1
hook.save()
signal.save()
return HttpResponse("OK")

View File

@ -12,7 +12,9 @@ class SignalList(LoginRequiredMixin, ObjectList):
list_template = "partials/signal-list.html"
model = Signal
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_args = ["type"]