fisk/core/views/hooks.py

178 lines
5.5 KiB
Python
Raw Normal View History

2022-11-21 07:20:12 +00:00
import re
from string import digits
2022-10-14 06:20:30 +00:00
import orjson
2022-10-14 06:20:30 +00:00
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, HttpResponseBadRequest
from pydantic import ValidationError
from rest_framework.parsers import JSONParser
2022-10-12 06:22:22 +00:00
from rest_framework.views import APIView
from core.forms import HookForm
from core.lib.schemas.drakdoo_s import DrakdooCallback
2022-12-01 19:32:50 +00:00
from core.models import Callback, Hook, Signal
2022-12-20 07:20:26 +00:00
from core.trading import market
2022-10-15 22:36:04 +00:00
from core.util import logs
from core.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
2022-10-15 22:24:03 +00:00
2022-10-15 22:34:55 +00:00
log = logs.get_logger(__name__)
2022-10-12 06:22:22 +00:00
2022-11-21 07:20:12 +00:00
def extract_price(message):
result = re.findall("\d+\.\d+", message) # noqa
if len(result) != 1:
log.error(f"Could not extract price from message: {message}")
return False
try:
log.debug(f"Extracted {result[0]} from '{message}'")
return float(result[0])
except ValueError:
return False
class HookAPI(APIView):
parser_classes = [JSONParser]
def post(self, request, hook_name):
2022-10-15 22:24:03 +00:00
log.debug(f"HookAPI POST: {request.data}")
# Try loading the JSON
2022-10-16 13:37:49 +00:00
# try:
# loaded_json = orjson.loads(request.data)
# except orjson.JSONDecodeError:
# return HttpResponseBadRequest("Invalid JSON")
2022-10-15 22:24:03 +00:00
# Try validating the JSON
try:
hook_resp = DrakdooCallback(**request.data)
2022-10-15 22:24:03 +00:00
except ValidationError as e:
log.error(f"HookAPI POST: {e}")
return HttpResponseBadRequest(e)
2022-11-21 07:20:12 +00:00
if hasattr(hook_resp, "market.price"):
try:
price = float(hook_resp.market.price)
except ValueError:
log.debug(
f"Could not extract price from message: {hook_resp.market.price}"
)
return HttpResponseBadRequest("Could not extract price from message")
else:
price = extract_price(hook_resp.message)
if not price:
log.debug(f"Could not extract price from message: {hook_resp.message}")
return HttpResponseBadRequest("Could not extract price from message")
base = hook_resp.market.item
quote = hook_resp.market.currency
symbol = f"{base.upper()}/{quote.upper()}"
data = {
"title": hook_resp.title,
"message": hook_resp.message,
"period": hook_resp.period,
"sent": hook_resp.timestamp.sent,
"trade": hook_resp.timestamp.trade,
"exchange": hook_resp.market.exchange,
"base": hook_resp.market.item,
"quote": hook_resp.market.currency,
"symbol": symbol,
"contract": hook_resp.market.contract,
"price": price,
}
log.debug("HookAPI callback: data: %s", data)
2022-10-15 22:24:03 +00:00
# Try getting the hook
2022-10-15 21:08:13 +00:00
try:
hook = Hook.objects.get(hook=hook_name)
2022-10-15 21:08:13 +00:00
except Hook.DoesNotExist:
return HttpResponseBadRequest("Hook does not exist.")
2022-10-15 22:24:03 +00:00
2022-12-01 19:32:50 +00:00
# Try getting the signal
2022-12-06 19:59:10 +00:00
# AUCAD 3M Stoch Exit: C$2419.64 at OANDA
# >>> a.split(":")[0:]
# ['AUCAD 3M Stoch Exit', ' C$2419.64 at OANDA']
# >>> a.split(":")[0].split(" ")[2:]
# ['Stoch', 'Exit']
# >>> " ".join(a.split(":")[0].split(" ")[2:])
# 'Stoch Exit'
signal_name = " ".join(hook_resp.message.split(":")[0].split(" ")[2:])
for x in signal_name:
if x in digits:
signal_name = signal_name.replace(x, "?")
2022-12-01 19:32:50 +00:00
try:
signal = Signal.objects.get(signal=signal_name)
2022-12-01 19:32:50 +00:00
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")
2022-12-01 19:32:50 +00:00
# Set the signal relation
data["signal"] = signal
2022-10-15 22:24:03 +00:00
# Create the callback object
callback = Callback.objects.create(hook=hook, **data)
callback.save()
market.process_callback(callback)
2022-10-15 22:24:03 +00:00
# Bump received count
hook.received = hook.received + 1
2022-12-01 19:32:50 +00:00
signal.received = signal.received + 1
2022-10-15 22:10:18 +00:00
hook.save()
2022-12-01 19:32:50 +00:00
signal.save()
return HttpResponse("OK")
def get(self, request, hook_name):
2022-11-03 15:59:27 +00:00
try:
2022-12-06 20:12:24 +00:00
hook = Hook.objects.get(hook=hook_name)
2022-11-03 15:59:27 +00:00
except Hook.DoesNotExist:
return HttpResponseBadRequest("Hook does not exist.")
2022-12-06 20:12:24 +00:00
signals = Signal.objects.filter(hook=hook)
2022-12-06 20:12:24 +00:00
return_data = {
"name": hook.name,
"hook": hook.hook,
"hook_id": hook.id,
"signals": len(signals),
}
return HttpResponse(orjson.dumps(return_data), content_type="application/json")
class HookList(LoginRequiredMixin, ObjectList):
# window_content = "window-content/hooks.html"
list_template = "partials/hook-list.html"
model = Hook
page_title = "List of active URL endpoints for receiving hooks."
2022-11-04 07:20:55 +00:00
page_subtitle = (
"Add URLs here to receive Drakdoo callbacks. "
"Make then unique and hard to guess!"
)
2022-10-12 06:22:22 +00:00
2022-10-29 13:05:01 +00:00
list_url_name = "hooks"
list_url_args = ["type"]
submit_url_name = "hook_create"
2022-10-15 17:45:25 +00:00
class HookCreate(LoginRequiredMixin, ObjectCreate):
model = Hook
form_class = HookForm
2022-10-29 13:05:01 +00:00
submit_url_name = "hook_create"
class HookUpdate(LoginRequiredMixin, ObjectUpdate):
model = Hook
form_class = HookForm
2022-10-29 13:05:01 +00:00
submit_url_name = "hook_update"
2022-10-15 17:45:25 +00:00
class HookDelete(LoginRequiredMixin, ObjectDelete):
model = Hook