|
|
|
@ -138,46 +138,76 @@ def get_trade_size_in_base(direction, account, strategy, cash_balance, base):
|
|
|
|
|
return trade_size_in_base
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_tp_sl(direction, strategy, price):
|
|
|
|
|
def get_tp(direction, take_profit_percent, price):
|
|
|
|
|
"""
|
|
|
|
|
Get the take profit and stop loss prices.
|
|
|
|
|
Get the take profit price.
|
|
|
|
|
:param direction: Direction of the trade
|
|
|
|
|
:param strategy: Strategy object
|
|
|
|
|
:param price: Price of the trade
|
|
|
|
|
:return: Take profit and stop loss prices
|
|
|
|
|
:param price: Entry price
|
|
|
|
|
"""
|
|
|
|
|
# Convert to ratio
|
|
|
|
|
take_profit_as_ratio = D(take_profit_percent) / D(100)
|
|
|
|
|
log.debug(f"Take profit as ratio: {take_profit_as_ratio}")
|
|
|
|
|
|
|
|
|
|
# Convert TP and SL to ratios
|
|
|
|
|
stop_loss_as_ratio = D(strategy.stop_loss_percent) / D(100)
|
|
|
|
|
take_profit_as_ratio = D(strategy.take_profit_percent) / D(100)
|
|
|
|
|
take_profit_var = D(price) * D(take_profit_as_ratio)
|
|
|
|
|
log.debug(f"Take profit var: {take_profit_var}")
|
|
|
|
|
|
|
|
|
|
if direction == "buy":
|
|
|
|
|
take_profit = D(price) + D(take_profit_var)
|
|
|
|
|
elif direction == "sell":
|
|
|
|
|
take_profit = D(price) - D(take_profit_var)
|
|
|
|
|
|
|
|
|
|
log.debug(f"Take profit: {take_profit}")
|
|
|
|
|
return take_profit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_sl(direction, stop_loss_percent, price, return_var=False):
|
|
|
|
|
"""
|
|
|
|
|
Get the stop loss price.
|
|
|
|
|
Also used for trailing stop loss.
|
|
|
|
|
:param direction: Direction of the trade
|
|
|
|
|
:param strategy: Strategy object
|
|
|
|
|
:param price: Entry price
|
|
|
|
|
"""
|
|
|
|
|
# Convert to ratio
|
|
|
|
|
stop_loss_as_ratio = D(stop_loss_percent) / D(100)
|
|
|
|
|
log.debug(f"Stop loss as ratio: {stop_loss_as_ratio}")
|
|
|
|
|
log.debug(f"Take profit as ratio: {take_profit_as_ratio}")
|
|
|
|
|
|
|
|
|
|
# Calculate the TP and SL prices by multiplying with the price
|
|
|
|
|
stop_loss_var = D(price) * D(stop_loss_as_ratio)
|
|
|
|
|
take_profit_var = D(price) * D(take_profit_as_ratio)
|
|
|
|
|
log.debug(f"Stop loss var: {stop_loss_var}")
|
|
|
|
|
log.debug(f"Take profit var: {take_profit_var}")
|
|
|
|
|
|
|
|
|
|
# Flip addition operators for inverse trade directions
|
|
|
|
|
# * We need to subtract the SL for buys, since we are losing money if
|
|
|
|
|
# the price goes down
|
|
|
|
|
# * We need to add the TP for buys, since we are gaining money if
|
|
|
|
|
# the price goes up
|
|
|
|
|
# * We need to add the SL for sells, since we are losing money if
|
|
|
|
|
# the price goes up
|
|
|
|
|
# * We need to subtract the TP for sells, since we are gaining money if
|
|
|
|
|
# the price goes down
|
|
|
|
|
if return_var:
|
|
|
|
|
return stop_loss_var
|
|
|
|
|
|
|
|
|
|
if direction == "buy":
|
|
|
|
|
stop_loss = D(price) - D(stop_loss_var)
|
|
|
|
|
take_profit = D(price) + D(take_profit_var)
|
|
|
|
|
elif direction == "sell":
|
|
|
|
|
stop_loss = D(price) + D(stop_loss_var)
|
|
|
|
|
take_profit = D(price) - D(take_profit_var)
|
|
|
|
|
|
|
|
|
|
log.debug(f"Stop loss: {stop_loss}")
|
|
|
|
|
log.debug(f"Take profit: {take_profit}")
|
|
|
|
|
return stop_loss
|
|
|
|
|
|
|
|
|
|
return (stop_loss, take_profit)
|
|
|
|
|
|
|
|
|
|
def get_tp_sl(direction, strategy, price):
|
|
|
|
|
"""
|
|
|
|
|
Get the take profit and stop loss prices.
|
|
|
|
|
:param direction: Direction of the trade
|
|
|
|
|
:param strategy: Strategy object
|
|
|
|
|
:param price: Price of the trade
|
|
|
|
|
:return: Take profit and stop loss prices
|
|
|
|
|
"""
|
|
|
|
|
take_profit = get_tp(direction, strategy.take_profit_percent, price)
|
|
|
|
|
stop_loss = get_sl(direction, strategy.stop_loss_percent, price)
|
|
|
|
|
cast = {"tp": take_profit, "sl": stop_loss}
|
|
|
|
|
|
|
|
|
|
# Look up the TSL if required by the strategy
|
|
|
|
|
if strategy.trailing_stop_loss_percent:
|
|
|
|
|
trailing_stop_loss = get_sl(
|
|
|
|
|
direction, strategy.trailing_stop_loss_percent, price, return_var=True
|
|
|
|
|
)
|
|
|
|
|
cast["tsl"] = trailing_stop_loss
|
|
|
|
|
|
|
|
|
|
return cast
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_price_bound(direction, strategy, price, current_price):
|
|
|
|
@ -306,8 +336,13 @@ def execute_strategy(callback, strategy):
|
|
|
|
|
direction, account, strategy, cash_balance, base
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Calculate TP/SL
|
|
|
|
|
stop_loss, take_profit = get_tp_sl(direction, strategy, price)
|
|
|
|
|
# Calculate TP/SL/TSL
|
|
|
|
|
protection = get_tp_sl(direction, strategy, current_price)
|
|
|
|
|
stop_loss = protection["sl"]
|
|
|
|
|
take_profit = protection["tp"]
|
|
|
|
|
trailing_stop_loss = None
|
|
|
|
|
if "tsl" in protection:
|
|
|
|
|
trailing_stop_loss = protection["tsl"]
|
|
|
|
|
|
|
|
|
|
# Calculate price bound and round to the display precision
|
|
|
|
|
price_bound = get_price_bound(direction, strategy, price, current_price)
|
|
|
|
@ -315,14 +350,6 @@ def execute_strategy(callback, strategy):
|
|
|
|
|
return
|
|
|
|
|
price_bound = round(price_bound, display_precision)
|
|
|
|
|
|
|
|
|
|
# # Use the price reported by the callback for limit orders
|
|
|
|
|
# if type == "limit":
|
|
|
|
|
# price_for_trade = price
|
|
|
|
|
|
|
|
|
|
# # Use the price bound for market orders
|
|
|
|
|
# elif type == "market":
|
|
|
|
|
# price_for_trade = price_bound
|
|
|
|
|
|
|
|
|
|
# Create object, note that the amount is rounded to the trade precision
|
|
|
|
|
new_trade = Trade.objects.create(
|
|
|
|
|
user=user,
|
|
|
|
@ -339,6 +366,11 @@ def execute_strategy(callback, strategy):
|
|
|
|
|
take_profit=float(round(take_profit, display_precision)),
|
|
|
|
|
direction=direction,
|
|
|
|
|
)
|
|
|
|
|
# Add TSL if applicable
|
|
|
|
|
if trailing_stop_loss:
|
|
|
|
|
new_trade.trailing_stop_loss = float(
|
|
|
|
|
round(trailing_stop_loss, display_precision)
|
|
|
|
|
)
|
|
|
|
|
new_trade.save()
|
|
|
|
|
info = new_trade.post()
|
|
|
|
|
log.debug(f"Posted trade: {info}")
|
|
|
|
|