Refactor and ignore n/a exchange callbacks

This commit is contained in:
Mark Veidemanis 2022-11-10 07:20:20 +00:00
parent 8b52063473
commit c3d908341a
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
6 changed files with 40 additions and 23 deletions

View File

@ -1,20 +1,20 @@
from decimal import Decimal as D from decimal import Decimal as D
from alpaca.common.exceptions import APIError from core.exchanges import GenericAPIError
from core.models import Strategy, Trade from core.models import Strategy, Trade
from core.util import logs from core.util import logs
from core.exchanges import GenericAPIError
log = logs.get_logger(__name__) log = logs.get_logger(__name__)
def to_usd(account, amount, from_currency):
if account.exchange == "alpaca": # def to_usd(account, amount, from_currency):
separator = "/" # if account.exchange == "alpaca":
elif account.exchange == "oanda": # separator = "/"
separator = "_" # elif account.exchange == "oanda":
symbol = f"{from_currency.upper()}{separator}{to_currency.upper()}" # separator = "_"
prices = account.client.get_currencies([symbol]) # symbol = f"{from_currency.upper()}{separator}{to_currency.upper()}"
# prices = account.client.get_currencies([symbol])
def to_currency(direction, account, amount, from_currency, to_currency): def to_currency(direction, account, amount, from_currency, to_currency):
if account.exchange == "alpaca": if account.exchange == "alpaca":
@ -41,6 +41,7 @@ def to_currency(direction, account, amount, from_currency, to_currency):
return converted return converted
def get_pair(account, base, quote): def get_pair(account, base, quote):
if account.exchange == "alpaca": if account.exchange == "alpaca":
separator = "/" separator = "/"
@ -52,17 +53,23 @@ def get_pair(account, base, quote):
return False return False
return symbol return symbol
def get_trade_size_in_base(direction, account, strategy, cash_balance, price, base, precision):
def get_trade_size_in_base(
direction, account, strategy, cash_balance, price, base, precision
):
trade_size_as_ratio = D(strategy.trade_size_percent) / D(100) trade_size_as_ratio = D(strategy.trade_size_percent) / D(100)
log.debug(f"Trade size as ratio: {trade_size_as_ratio}") log.debug(f"Trade size as ratio: {trade_size_as_ratio}")
amount_fiat = D(trade_size_as_ratio) * D(cash_balance) amount_fiat = D(trade_size_as_ratio) * D(cash_balance)
log.debug(f"Trade size: {amount_fiat}") log.debug(f"Trade size: {amount_fiat}")
# We can do this because the quote IS in $ or equivalent # We can do this because the quote IS in $ or equivalent
# trade_size_in_base = D(amount_fiat) / D(price) # trade_size_in_base = D(amount_fiat) / D(price)
trade_size_in_base = to_currency(direction, account, amount_fiat, account.currency, base) trade_size_in_base = to_currency(
direction, account, amount_fiat, account.currency, base
)
log.debug(f"Trade size in base: {trade_size_in_base}") log.debug(f"Trade size in base: {trade_size_in_base}")
return trade_size_in_base return trade_size_in_base
def get_tp_sl(direction, strategy, price): def get_tp_sl(direction, strategy, price):
stop_loss_as_ratio = D(strategy.stop_loss_percent) / D(100) stop_loss_as_ratio = D(strategy.stop_loss_percent) / D(100)
take_profit_as_ratio = D(strategy.take_profit_percent) / D(100) take_profit_as_ratio = D(strategy.take_profit_percent) / D(100)
@ -85,6 +92,7 @@ def get_tp_sl(direction, strategy, price):
log.debug(f"Take profit: {take_profit}") log.debug(f"Take profit: {take_profit}")
return (stop_loss, take_profit) return (stop_loss, take_profit)
def get_price_bound(direction, strategy, price): def get_price_bound(direction, strategy, price):
price_slippage_as_ratio = D(strategy.price_slippage_percent) / D(100) price_slippage_as_ratio = D(strategy.price_slippage_percent) / D(100)
log.debug(f"Price slippage as ratio: {price_slippage_as_ratio}") log.debug(f"Price slippage as ratio: {price_slippage_as_ratio}")
@ -146,7 +154,9 @@ def execute_strategy(callback, strategy):
# type = "limit" # type = "limit"
type = "market" type = "market"
trade_size_in_base = get_trade_size_in_base(direction, account, strategy, cash_balance, price, base, display_precision) trade_size_in_base = get_trade_size_in_base(
direction, account, strategy, cash_balance, price, base, display_precision
)
stop_loss, take_profit = get_tp_sl(direction, strategy, price) stop_loss, take_profit = get_tp_sl(direction, strategy, price)
price_bound = round(get_price_bound(direction, strategy, price), display_precision) price_bound = round(get_price_bound(direction, strategy, price), display_precision)

View File

@ -353,6 +353,7 @@ AccountInstrumentsSchema = {
) )
} }
class OrderTransaction(BaseModel): class OrderTransaction(BaseModel):
id: str id: str
accountID: str accountID: str
@ -367,9 +368,11 @@ class OrderTransaction(BaseModel):
positionFill: str positionFill: str
reason: str reason: str
class OrderCreate(BaseModel): class OrderCreate(BaseModel):
orderCreateTransaction: OrderTransaction orderCreateTransaction: OrderTransaction
OrderCreateSchema = { OrderCreateSchema = {
"id": "orderCreateTransaction.id", "id": "orderCreateTransaction.id",
"accountID": "orderCreateTransaction.accountID", "accountID": "orderCreateTransaction.accountID",
@ -385,18 +388,22 @@ OrderCreateSchema = {
"reason": "orderCreateTransaction.reason", "reason": "orderCreateTransaction.reason",
} }
class PriceBid(BaseModel): class PriceBid(BaseModel):
price: str price: str
liquidity: int liquidity: int
class PriceAsk(BaseModel): class PriceAsk(BaseModel):
price: str price: str
liquidity: int liquidity: int
class PriceQuoteHomeConversionFactors(BaseModel): class PriceQuoteHomeConversionFactors(BaseModel):
positiveUnits: str positiveUnits: str
negativeUnits: str negativeUnits: str
class Price(BaseModel): class Price(BaseModel):
type: str type: str
time: str time: str
@ -409,10 +416,12 @@ class Price(BaseModel):
quoteHomeConversionFactors: PriceQuoteHomeConversionFactors quoteHomeConversionFactors: PriceQuoteHomeConversionFactors
instrument: str instrument: str
class PricingInfo(BaseModel): class PricingInfo(BaseModel):
time: str time: str
prices: list[Price] prices: list[Price]
PricingInfoSchema = { PricingInfoSchema = {
"time": "time", "time": "time",
"prices": ( "prices": (

View File

@ -69,10 +69,7 @@ class User(AbstractUser):
class Account(models.Model): class Account(models.Model):
EXCHANGE_CHOICES = ( EXCHANGE_CHOICES = (("alpaca", "Alpaca"), ("oanda", "OANDA"))
("alpaca", "Alpaca"),
("oanda", "OANDA")
)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
exchange = models.CharField(choices=EXCHANGE_CHOICES, max_length=255) exchange = models.CharField(choices=EXCHANGE_CHOICES, max_length=255)

View File

@ -1,11 +1,9 @@
from django import template
import orjson import orjson
from django import template
register = template.Library() register = template.Library()
@register.filter @register.filter
def pretty(data): def pretty(data):
return orjson.dumps( return orjson.dumps(data, option=orjson.OPT_INDENT_2).decode("utf-8")
data, option=orjson.OPT_INDENT_2
).decode("utf-8")

View File

@ -1,5 +1,5 @@
import uuid import uuid
import orjson
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from django.shortcuts import render from django.shortcuts import render

View File

@ -78,6 +78,9 @@ class HookAPI(APIView):
except Hook.DoesNotExist: except Hook.DoesNotExist:
return HttpResponseBadRequest("Hook does not exist.") return HttpResponseBadRequest("Hook does not exist.")
if data["exchange"].lower() == "n/a":
log.debug("HookAPI callback: exchange is N/A, skipping")
return HttpResponse("OK")
# 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()