From 483333bf28ca003fd1bf2fd5e581ca77b17a95e1 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Thu, 5 Jan 2023 19:46:18 +0000 Subject: [PATCH] Test checking maximum risk with market data --- core/exchanges/common.py | 6 ++ core/tests/trading/test_risk.py | 101 +++++++++++++++++++++++++++++--- core/trading/risk.py | 9 +-- 3 files changed, 104 insertions(+), 12 deletions(-) diff --git a/core/exchanges/common.py b/core/exchanges/common.py index fba62d5..9086da0 100644 --- a/core/exchanges/common.py +++ b/core/exchanges/common.py @@ -23,10 +23,13 @@ def get_balance_hook(user_id, user_name, account_id, account_name, balance): def tp_price_to_percent(tp_price, current_price, current_units, unrealised_pl): # Is this right? pl_per_unit = D(unrealised_pl) / D(current_units) + print("pl_per_unit: ", pl_per_unit) initial_price = D(current_price) - pl_per_unit + print("initial_price: ", initial_price) # Get the percent change of the TP price from the initial price. change_percent = ((D(tp_price) - initial_price) / initial_price) * 100 + print("change_percent: ", change_percent) # Doesn't check direction return abs(round(change_percent, 5)) @@ -35,10 +38,13 @@ def tp_price_to_percent(tp_price, current_price, current_units, unrealised_pl): def sl_price_to_percent(sl_price, current_price, current_units, unrealised_pl): # Is this right? pl_per_unit = D(unrealised_pl) / D(current_units) + print("pl_per_unit: ", pl_per_unit) initial_price = D(current_price) - pl_per_unit + print("initial_price: ", initial_price) # Get the percent change of the SL price from the initial price. change_percent = ((D(sl_price) - initial_price) / initial_price) * 100 + print("change_percent: ", change_percent) # Doesn't check direction return abs(round(change_percent, 5)) diff --git a/core/tests/trading/test_risk.py b/core/tests/trading/test_risk.py index 3974e58..50f29aa 100644 --- a/core/tests/trading/test_risk.py +++ b/core/tests/trading/test_risk.py @@ -1,5 +1,6 @@ from django.test import TestCase +from core.exchanges.common import convert_open_trades from core.models import RiskModel, User from core.trading import risk @@ -23,9 +24,9 @@ class RiskModelTestCase(TestCase): "symbol": "XXXYYY", "side": "BUY", # We already calculated the TP percent loss relative to the account size - "tp_percent": 9, - "sl_percent": 9, - "tsl_percent": 9, + "take_profit_percent": 9, + "stop_loss_percent": 9, + "trailing_stop_loss_percent": 9, } def test_check_max_loss(self): @@ -73,8 +74,8 @@ class RiskModelTestCase(TestCase): multiple trades. """ trade = self.trade.copy() - trade["sl_percent"] = 1 - trade["tsl_percent"] = 1 + trade["stop_loss_percent"] = 1 + trade["trailing_stop_loss_percent"] = 1 account_trades = [trade] * 9 allowed = risk.check_max_risk(self.risk_model, account_trades) self.assertTrue(allowed) @@ -85,7 +86,7 @@ class RiskModelTestCase(TestCase): risked is exactly the max risk limit. """ trade = self.trade.copy() - trade["sl_percent"] = 10 + trade["stop_loss_percent"] = 10 account_trades = [trade] allowed = risk.check_max_risk(self.risk_model, account_trades) self.assertFalse(allowed) @@ -96,8 +97,8 @@ class RiskModelTestCase(TestCase): risked is exactly the max risk limit with multiple trades. """ trade = self.trade.copy() - trade["sl_percent"] = 1 - trade["tsl_percent"] = 1 + trade["stop_loss_percent"] = 1 + trade["trailing_stop_loss_percent"] = 1 account_trades = [trade] * 10 allowed = risk.check_max_risk(self.risk_model, account_trades) self.assertFalse(allowed) @@ -189,3 +190,87 @@ class RiskModelTestCase(TestCase): account_trades = [trade1, trade2, trade1, trade2, trade1, trade2] allowed = risk.check_max_open_trades_per_symbol(self.risk_model, account_trades) self.assertFalse(allowed) + + def check_max_risk_market_data(self): + """ + Check that we can open a trade within the max risk limit with market data. + """ + trade = { + "id": "abd123", + "symbol": "EUR_USD", + "currentUnits": 100, + "side": "long", + "state": "open", + "price": 1.0, # initial + "unrealizedPL": 0, # price == initial + "stopLossOrder": { + "price": 0.95, # down by 5%, 5% risk + }, + } + converted = convert_open_trades([trade]) + self.assertEqual(converted[0]["stop_loss_percent"], 5) + max_risk_check = risk.check_max_risk(self.risk_model, converted) + self.assertTrue(max_risk_check) # 5% risk is fine + + def check_max_risk_market_data_multiple(self): + """ + Check that we can open a trade within the max risk limit with market data + and multiple trades. + """ + trade = { + "id": "abd123", + "symbol": "EUR_USD", + "currentUnits": 100, + "side": "long", + "state": "open", + "price": 1.0, # initial + "unrealizedPL": 0, # price == initial + "stopLossOrder": { + "price": 0.96, # down by 4%, 4% risk + }, + } + converted = convert_open_trades([trade, trade]) + max_risk_check = risk.check_max_risk(self.risk_model, converted) + self.assertTrue(max_risk_check) # 8% risk is fine + + def check_max_risk_market_data_fail(self): + """ + Check that we can not open a trade outside the max risk limit with market data. + """ + trade = { + "id": "abd123", + "symbol": "EUR_USD", + "currentUnits": 100, + "side": "long", + "state": "open", + "price": 1.0, # initial + "unrealizedPL": 0, # price == initial + "stopLossOrder": { + "price": 0.9, # down by 10%, 10% risk + }, + } + converted = convert_open_trades([trade]) + self.assertEqual(converted[0]["stop_loss_percent"], 10) + max_risk_check = risk.check_max_risk(self.risk_model, converted) + self.assertFalse(max_risk_check) # 10% risk is too much + + def check_max_risk_market_data_fail_multiple(self): + """ + Check that we can not open a trade outside the max risk limit with market data + and multiple trades. + """ + trade = { + "id": "abd123", + "symbol": "EUR_USD", + "currentUnits": 100, + "side": "long", + "state": "open", + "price": 1.0, # initial + "unrealizedPL": 0, # price == initial + "stopLossOrder": { + "price": 0.95, # down by 5%, 5% risk + }, + } + converted = convert_open_trades([trade, trade]) + max_risk_check = risk.check_max_risk(self.risk_model, converted) + self.assertFalse(max_risk_check) # 10% risk is too much diff --git a/core/trading/risk.py b/core/trading/risk.py index 1ad20e2..15bdff2 100644 --- a/core/trading/risk.py +++ b/core/trading/risk.py @@ -15,11 +15,12 @@ def check_max_risk(risk_model, account_trades): total_risk = 0 for trade in account_trades: max_tmp = [] - if "sl_percent" in trade: - max_tmp.append(trade["sl_percent"]) - if "tsl_percent" in trade: - max_tmp.append(trade["tsl_percent"]) + if "stop_loss_percent" in trade: + max_tmp.append(trade["stop_loss_percent"]) + if "trailing_stop_loss_percent" in trade: + max_tmp.append(trade["trailing_stop_loss_percent"]) total_risk += max(max_tmp) + print("Total risk: ", total_risk) return total_risk < max_risk_percent