Implement checking direction with assetfilter

This commit is contained in:
Mark Veidemanis 2023-02-13 17:47:47 +00:00
parent dcfb963be6
commit 0321aff9d5
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
4 changed files with 97 additions and 20 deletions

View File

@ -16,16 +16,55 @@ class AssetfilterTestCase(TestCase):
description="Test group", description="Test group",
) )
def test_get_allowed(self): def test_get_allowed_negative(self):
""" """
Test that the asset filter works. Test that the asset filter works on negative aggregations.
""" """
self.group.allowed = {"EUR_USD": True, "EUR_GBP": False} # We have negative news about EUR
self.assertTrue(assetfilter.get_allowed(self.group, "EUR_USD", "buy")) self.group.allowed = {"EUR": False}
self.assertFalse(assetfilter.get_allowed(self.group, "EUR_GBP", "sell")) self.group.save()
# Default true # This means that:
self.assertTrue(assetfilter.get_allowed(self.group, "nonexistent", "sell")) # * base == EUR: long is not allowed, short is allowed
# * quote == EUR: long is allowed, short is not allowed
# We are betting on it going down, so we short base, and long quote.
# Test that short on base of EUR is allowed
self.assertTrue(assetfilter.get_allowed(self.group, "EUR", "USD", "short"))
# Test that long on quote of EUR is allowed
self.assertTrue(assetfilter.get_allowed(self.group, "USD", "EUR", "long"))
# Test that long on base of EUR is not allowed
self.assertFalse(assetfilter.get_allowed(self.group, "EUR", "USD", "long"))
# Test that short on quote of EUR is not allowed
self.assertFalse(assetfilter.get_allowed(self.group, "USD", "EUR", "short"))
def test_get_allowed_positive(self):
"""
Test that the asset filter works on positive aggregations.
"""
# We have positive news about EUR
self.group.allowed = {"EUR": True}
self.group.save()
# This means that:
# * base == EUR: long is allowed, short is not allowed
# * quote == EUR: long is not allowed, short is allowed
# We are betting on it going up, so we long base, and short quote.
# Test that long on base of EUR is allowed
self.assertTrue(assetfilter.get_allowed(self.group, "EUR", "USD", "long"))
# Test that short on quote of EUR is allowed
self.assertTrue(assetfilter.get_allowed(self.group, "USD", "EUR", "short"))
# Test that short on base of EUR is not allowed
self.assertFalse(assetfilter.get_allowed(self.group, "EUR", "USD", "short"))
# Test that long on quote of EUR is not allowed
self.assertFalse(assetfilter.get_allowed(self.group, "USD", "EUR", "long"))
def test_check_asset_aggregation(self): def test_check_asset_aggregation(self):
""" """

View File

@ -1,22 +1,44 @@
def get_allowed(group, symbol, direction): def get_allowed(group, base, quote, direction):
""" """
Determine whether the trade is allowed according to the Asset Groups Determine whether the trade is allowed according to the group.
linked to the strategy. See tests for examples. The logic requires trading knowledge.
:param group: The group to check
:param base: The base currency
:param quote: The quote currency
:param direction: The direction of the trade
""" """
# TODO: figure out what to do with direction
allowed = group.allowed allowed = group.allowed
if not isinstance(allowed, dict): if not isinstance(allowed, dict):
return False return False
if symbol not in allowed:
return True
return allowed[symbol] # If our base has allowed == False, we can only short it, or long the quote
if base in allowed:
if not allowed[base]:
if direction == "long":
return False
else:
if direction == "short":
return False
# If our quote has allowed == False, we can only long it, or short the base
if quote in allowed:
if not allowed[quote]:
if direction == "short":
return False
else:
if direction == "long":
return False
return True
def check_asset_aggregation(value, trigger_above, trigger_below): def check_asset_aggregation(value, trigger_above, trigger_below):
""" """
Check if the value is within the bounds of the aggregation Check if the value is within the bounds of the aggregation.
:param value: The value to check
:param trigger_above: Only trigger if the value is above this
:param trigger_below: Only trigger if the value is below this
""" """
# If both are defined # If both are defined
if trigger_above is not None and trigger_below is not None: if trigger_above is not None and trigger_below is not None:

View File

@ -63,6 +63,22 @@ def check_conflicting_position(
new_symbol: str, new_symbol: str,
trade_side_opposite: str, trade_side_opposite: str,
): ):
"""
Determine if we have a conflicting position open.
:param func: Whether we are checking entries, exits or trends
:param position: Position dict
:param open_base: Base currency of the open position
:param open_quote: Quote currency of the open position
:param open_side: Side of the open position
:param open_symbol: Symbol of the open position
:param open_units: Units of the open position
:param new_base: Base currency of the new position
:param new_quote: Quote currency of the new position
:param new_side: Side of the new position
:param new_symbol: Symbol of the new position
:param trade_side_opposite: Opposite side of the trade
:return: dict of action and opposing position, or None
"""
if open_base == new_quote or open_quote == new_base: 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 we have a long on GBP/AUD, we can only place shorts on XAU/GBP.
if open_side != trade_side_opposite: if open_side != trade_side_opposite:
@ -85,10 +101,10 @@ def crossfilter(account, new_symbol, new_direction, func):
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
with an opposite direction to this one. with an opposite direction to this one.
:param account: Account object :param account: Account object
:param symbol: Symbol :param new_symbol: Symbol of the new position
:param direction: Direction of the trade :param new_direction: Direction of the new position
:param func: Whether we are checking entries or exits :param func: Whether we are checking entries, exits or trends
:return: dict of action and opposing position, or False :return: dict of action and opposing position, False or None
""" """
try: try:
# Only get the data we need # Only get the data we need

View File

@ -329,7 +329,7 @@ def execute_strategy(callback, strategy, func):
# Check against the asset groups # Check against the asset groups
if func == "entry" and strategy.assetgroup is not None: if func == "entry" and strategy.assetgroup is not None:
allowed = assetfilter.get_allowed(strategy, symbol, direction) allowed = assetfilter.get_allowed(strategy, base, quote, direction)
if not allowed: if not allowed:
log.debug( log.debug(
f"Denied trading {symbol} due to asset filter {strategy.assetgroup}" f"Denied trading {symbol} due to asset filter {strategy.assetgroup}"