Prevent betting against ourselves via inverted pairs

This commit is contained in:
Mark Veidemanis 2022-12-12 19:53:20 +00:00
parent 4218fdedbc
commit 1793b5cc5d
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
1 changed files with 133 additions and 21 deletions

View File

@ -8,7 +8,82 @@ from core.util import logs
log = logs.get_logger(__name__) log = logs.get_logger(__name__)
def crossfilter(account, symbol, direction, func): def check_existing_position(
func: str,
position: dict,
open_side: str,
open_symbol: str,
open_units: str,
new_side: str,
new_symbol: str,
trade_side_opposite: str,
):
# Check if we already have a position for the symbol
if open_symbol == new_symbol:
# If the live side is the inverse of what we want to do,
# we can't open a position
if open_side == trade_side_opposite:
# If there is a position open, we can't open a new one in the opposite
# direction
if open_units != "0":
# If we have a short on GBP/AUD, we can only place more shorts on
# GBP/AUD.
if func == "entry":
log.debug(
f"Refusing to open new {new_side} position on {new_symbol} due "
f"to {open_side} position on {open_symbol}"
)
return {
"action": "rejected",
"positions": position,
}
elif func == "exit":
log.debug(
(
f"Found {open_units} units of "
f"{open_symbol} on side {trade_side_opposite}"
)
)
# Pass back opposing side so we can close it
return {
"action": "close",
"side": trade_side_opposite,
"positions": position,
}
return False
def check_conflicting_position(
func: str,
position: dict,
open_base: str,
open_quote: str,
open_side: str,
open_symbol: str,
open_units: str,
new_base: str,
new_quote: str,
new_side: str,
new_symbol: str,
trade_side_opposite: str,
):
if open_base == new_quote or open_quote == new_base:
# If we have a long on GBP/AUD, we can only place shorts on XAU/GBP.
if open_side != trade_side_opposite:
if open_units != "0":
# Only do this for entries
if func == "entry":
log.debug(
f"Refusing to open {new_side} position on {new_symbol} due to "
f"{open_side} position on {open_symbol}"
)
return {
"action": "rejected",
"positions": position,
}
def crossfilter(account, new_symbol, new_direction, func):
""" """
Determine if we are betting against ourselves. Determine if we are betting against ourselves.
Checks open positions for the account, rejecting the trade if there is one Checks open positions for the account, rejecting the trade if there is one
@ -20,7 +95,11 @@ def crossfilter(account, symbol, direction, func):
:return: dict of action and opposing position, or False :return: dict of action and opposing position, or False
""" """
try: try:
position_info = account.client.get_position_info(symbol) # Only get the data we need
if func == "entry":
all_positions = account.client.get_all_positions()
else:
all_positions = [account.client.get_position_info(new_symbol)]
except GenericAPIError as e: except GenericAPIError as e:
if "No position exists for the specified instrument" in str(e): if "No position exists for the specified instrument" in str(e):
log.debug("No position exists for this symbol") log.debug("No position exists for this symbol")
@ -28,28 +107,61 @@ def crossfilter(account, symbol, direction, func):
else: else:
log.error(f"Error getting position info: {e}") log.error(f"Error getting position info: {e}")
return None return None
if direction == "buy": if new_direction == "buy":
opposing_side = "short" opposing_side = "short"
elif direction == "sell": new_side = "long"
elif new_direction == "sell":
opposing_side = "long" opposing_side = "long"
new_side = "short"
opposing_position_info = position_info[opposing_side] quotes = []
if opposing_position_info["units"] != "0": new_base, new_quote = new_symbol.split("_")
if func == "entry": for position in all_positions:
return {"action": "rejected", "positions": opposing_position_info} # For Forex, get a list of all the quotes.
elif func == "exit": # This is to prevent betting against ourselves.
log.debug( # Consider we have a long position open, EUR/USD, and we want to open a
( # long position on USD/JPY. If the first goes up, the second one will go
f"Found {opposing_position_info['units']} units of " # down just as much. We won't make any money.
f"{symbol} on side {opposing_side}" if "_" in position["symbol"]:
open_base, open_quote = position["symbol"].split("_")
quotes.append(open_quote)
open_symbol = position["symbol"]
open_side = position["side"]
open_base, open_quote = open_symbol.split("_")
# Check if we already have a position
existing_position_check = check_existing_position(
func=func,
position=position,
open_side=open_side,
open_symbol=open_symbol,
open_units=position["units"],
new_side=new_side,
new_symbol=new_symbol,
trade_side_opposite=opposing_side,
) )
if existing_position_check:
return existing_position_check
# Check if we are betting against ourselves
conflicting_position_check = check_conflicting_position(
func=func,
position=position,
open_base=open_base,
open_quote=open_quote,
open_side=open_side,
open_symbol=open_symbol,
open_units=position["units"],
new_base=new_base,
new_quote=new_quote,
new_side=new_side,
new_symbol=new_symbol,
trade_side_opposite=opposing_side,
) )
# Pass back opposing side so we can close it if conflicting_position_check:
return { return conflicting_position_check
"action": "close",
"side": opposing_side,
"positions": opposing_position_info,
}
return False return False