Skip to content

Commit af989dd

Browse files
committed
Fix take profit rules
1 parent 2bd92f5 commit af989dd

39 files changed

+1189
-468
lines changed

investing_algorithm_framework/__init__.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
from .domain import ApiException, combine_backtests, PositionSize, \
1212
OrderType, OperationalException, OrderStatus, OrderSide, \
1313
TimeUnit, TimeInterval, Order, Portfolio, Backtest, DataError, \
14-
Position, TimeFrame, INDEX_DATETIME, MarketCredential, \
14+
Position, TimeFrame, INDEX_DATETIME, MarketCredential, TakeProfitRule, \
1515
PortfolioConfiguration, RESOURCE_DIRECTORY, AWS_LAMBDA_LOGGING_CONFIG, \
16-
Trade, SYMBOLS, RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT, \
16+
Trade, APP_MODE, AppMode, DATETIME_FORMAT, \
1717
BacktestDateRange, convert_polars_to_pandas, BacktestRun, \
18-
DEFAULT_LOGGING_CONFIG, DataType, DataProvider, \
19-
TradeStatus, TradeRiskType, generate_backtest_summary_metrics, \
18+
DEFAULT_LOGGING_CONFIG, DataType, DataProvider, StopLossRule, \
19+
TradeStatus, generate_backtest_summary_metrics, \
2020
APPLICATION_DIRECTORY, DataSource, OrderExecutor, PortfolioProvider, \
2121
SnapshotInterval, AWS_S3_STATE_BUCKET_NAME, BacktestEvaluationFocus
2222
from .infrastructure import AzureBlobStorageStateHandler, \
@@ -48,7 +48,8 @@
4848
get_current_average_trade_gain, get_current_average_trade_duration, \
4949
get_current_average_trade_loss, get_negative_trades, \
5050
get_positive_trades, get_number_of_trades, get_current_win_rate, \
51-
get_current_win_loss_ratio, create_backtest_metrics_for_backtest
51+
get_current_win_loss_ratio, create_backtest_metrics_for_backtest, \
52+
TradeTakeProfitService, TradeStopLossService
5253

5354

5455
__all__ = [
@@ -76,8 +77,6 @@
7677
"TimeFrame",
7778
"MarketCredential",
7879
"OperationalException",
79-
"SYMBOLS",
80-
"RESERVED_BALANCES",
8180
"APP_MODE",
8281
"AppMode",
8382
"DATETIME_FORMAT",
@@ -88,7 +87,6 @@
8887
"DEFAULT_LOGGING_CONFIG",
8988
"BacktestReport",
9089
"TradeStatus",
91-
"TradeRiskType",
9290
"Context",
9391
"APPLICATION_DIRECTORY",
9492
"download",
@@ -193,5 +191,9 @@
193191
"load_backtests_from_directory",
194192
"save_backtests_to_directory",
195193
"DataError",
196-
"create_backtest_metrics_for_backtest"
194+
"create_backtest_metrics_for_backtest",
195+
"TakeProfitRule",
196+
"StopLossRule",
197+
"TradeStopLossService",
198+
"TradeTakeProfitService"
197199
]

investing_algorithm_framework/app/app.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ def initialize_data_sources_backtest(
452452
# Prepare the backtest data for each data provider
453453
if not show_progress:
454454
for _, data_provider in data_providers:
455+
455456
data_provider.prepare_backtest_data(
456457
backtest_start_date=backtest_date_range.start_date,
457458
backtest_end_date=backtest_date_range.end_date
@@ -616,7 +617,12 @@ def run(self, number_of_iterations: int = None):
616617

617618
trade_order_evaluator = DefaultTradeOrderEvaluator(
618619
trade_service=self.container.trade_service(),
619-
order_service=self.container.order_service()
620+
order_service=self.container.order_service(),
621+
trade_stop_loss_service=self.container
622+
.trade_stop_loss_service(),
623+
trade_take_profit_service=self.container
624+
.trade_take_profit_service(),
625+
configuration_service=self.container.configuration_service()
620626
)
621627
event_loop_service = EventLoopService(
622628
configuration_service=self.container.configuration_service(),
@@ -1368,7 +1374,11 @@ def run_backtest(
13681374
)
13691375
trade_order_evaluator = BacktestTradeOrderEvaluator(
13701376
trade_service=self.container.trade_service(),
1371-
order_service=self.container.order_service()
1377+
order_service=self.container.order_service(),
1378+
trade_stop_loss_service=self.container.trade_stop_loss_service(),
1379+
trade_take_profit_service=self.container
1380+
.trade_take_profit_service(),
1381+
configuration_service=self.container.configuration_service()
13721382
)
13731383
event_loop_service.initialize(
13741384
algorithm=algorithm,

investing_algorithm_framework/app/context.py

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
from investing_algorithm_framework.services import ConfigurationService, \
66
MarketCredentialService, OrderService, PortfolioConfigurationService, \
7-
PortfolioService, PositionService, TradeService, DataProviderService
7+
PortfolioService, PositionService, TradeService, DataProviderService, \
8+
TradeStopLossService, TradeTakeProfitService
89
from investing_algorithm_framework.domain import OrderStatus, OrderType, \
910
OrderSide, OperationalException, Portfolio, RoundingService, \
10-
BACKTESTING_FLAG, INDEX_DATETIME, TradeRiskType, Order, \
11-
Position, Trade, TradeStatus, MarketCredential
11+
BACKTESTING_FLAG, INDEX_DATETIME, Order, \
12+
Position, Trade, TradeStatus, MarketCredential, TradeStopLoss, \
13+
TradeTakeProfit
1214

1315
logger = logging.getLogger("investing_algorithm_framework")
1416

@@ -29,6 +31,8 @@ def __init__(
2931
order_service: OrderService,
3032
market_credential_service: MarketCredentialService,
3133
trade_service: TradeService,
34+
trade_stop_loss_service: TradeStopLossService,
35+
trade_take_profit_service: TradeTakeProfitService,
3236
data_provider_service: DataProviderService
3337
):
3438
self.configuration_service: ConfigurationService = \
@@ -42,6 +46,10 @@ def __init__(
4246
market_credential_service
4347
self.data_provider_service: DataProviderService = data_provider_service
4448
self.trade_service: TradeService = trade_service
49+
self.trade_stop_loss_service: TradeStopLossService = \
50+
trade_stop_loss_service
51+
self.trade_take_profit_service: TradeTakeProfitService = \
52+
trade_take_profit_service
4553

4654
@property
4755
def config(self):
@@ -1372,9 +1380,10 @@ def add_stop_loss(
13721380
self,
13731381
trade: Trade,
13741382
percentage: float,
1375-
trade_risk_type=TradeRiskType.FIXED,
1383+
trailing: bool = False,
13761384
sell_percentage: float = 100,
1377-
):
1385+
created_at: datetime = None,
1386+
) -> TradeStopLoss:
13781387
"""
13791388
Function to add a stop loss to a trade.
13801389
@@ -1397,30 +1406,34 @@ def add_stop_loss(
13971406
of the open price that the stop loss should
13981407
be set at. This must be a positive
13991408
number, e.g. 5 for 5%, or 10 for 10%.
1400-
trade_risk_type (TradeRiskType): The type of the stop
1401-
loss, fixed or trailing
1409+
trailing (bool): Whether the stop loss should be trailing
1410+
or fixed.
14021411
sell_percentage (float): float representing the
14031412
percentage of the trade that should be sold if the
14041413
stop loss is triggered
1414+
created_at: datetime: The date and time when the stop loss
1415+
was created. If not specified, the current date and time
1416+
will be used.
14051417
14061418
Returns:
14071419
None
14081420
"""
1409-
self.trade_service.add_stop_loss(
1421+
return self.trade_service.add_stop_loss(
14101422
trade,
14111423
percentage=percentage,
1412-
trade_risk_type=trade_risk_type,
1424+
trailing=trailing,
14131425
sell_percentage=sell_percentage,
1426+
created_at=created_at,
14141427
)
1415-
return self.trade_service.get(trade.id)
14161428

14171429
def add_take_profit(
14181430
self,
14191431
trade: Trade,
14201432
percentage: float,
1421-
trade_risk_type=TradeRiskType.FIXED,
1433+
trailing: bool = False,
14221434
sell_percentage: float = 100,
1423-
) -> None:
1435+
created_at: datetime = None,
1436+
) -> TradeTakeProfit:
14241437
"""
14251438
Function to add a take profit to a trade. This function will add a
14261439
take profit to the specified trade. If the take profit is triggered,
@@ -1445,22 +1458,25 @@ def add_take_profit(
14451458
of the open price that the stop loss should
14461459
be set at. This must be a positive
14471460
number, e.g. 5 for 5%, or 10 for 10%.
1448-
trade_risk_type (TradeRiskType): The type of the stop
1449-
loss, fixed or trailing
1461+
trailing (bool): Whether the take profit should be trailing
1462+
or fixed.
14501463
sell_percentage (float): float representing the
14511464
percentage of the trade that should be sold if the
14521465
stop loss is triggered
1466+
created_at: datetime: The date and time when the take profit
1467+
was created. If not specified, the current date and time
1468+
will be used.
14531469
14541470
Returns:
14551471
None
14561472
"""
1457-
self.trade_service.add_take_profit(
1473+
return self.trade_service.add_take_profit(
14581474
trade,
14591475
percentage=percentage,
1460-
trade_risk_type=trade_risk_type,
1476+
trailing=trailing,
14611477
sell_percentage=sell_percentage,
1478+
created_at=created_at,
14621479
)
1463-
return self.trade_service.get(trade.id)
14641480

14651481
def close_trade(self, trade, precision=None) -> None:
14661482
"""
@@ -1665,3 +1681,45 @@ def get_trading_symbol(self, portfolio_id=None):
16651681
portfolio = self.portfolio_service.get(portfolio_id)
16661682

16671683
return portfolio.trading_symbol
1684+
1685+
def get_take_profits(
1686+
self, triggered: bool = None
1687+
) -> List[TradeTakeProfit]:
1688+
"""
1689+
Function to get all take profits. If the triggered parameter
1690+
is specified, the function will return all take profits that
1691+
match the triggered status.
1692+
1693+
Args:
1694+
triggered (bool): The triggered status of the take profits
1695+
1696+
Returns:
1697+
List[TradeTakeProfit]: A list of take profits
1698+
"""
1699+
query_params = {}
1700+
1701+
if triggered is not None:
1702+
query_params["triggered"] = triggered
1703+
1704+
return self.trade_take_profit_service.get_all(query_params)
1705+
1706+
def get_stop_losses(
1707+
self, triggered: bool = None
1708+
) -> List[TradeStopLoss]:
1709+
"""
1710+
Function to get all stop losses. If the triggered parameter
1711+
is specified, the function will return all stop losses that
1712+
match the triggered status.
1713+
1714+
Args:
1715+
triggered (bool): The triggered status of the stop losses
1716+
1717+
Returns:
1718+
List[TradeStopLoss]: A list of stop losses
1719+
"""
1720+
query_params = {}
1721+
1722+
if triggered is not None:
1723+
query_params["triggered"] = triggered
1724+
1725+
return self.trade_stop_loss_service.get_all(query_params)

investing_algorithm_framework/app/eventloop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ def start(
351351
sorted_times,
352352
total=len(sorted_times),
353353
colour="GREEN",
354-
desc="Running backtest"
354+
desc="Running event backtest"
355355
):
356356
self._configuration_service.add_value(
357357
INDEX_DATETIME, current_time

investing_algorithm_framework/app/reporting/ascii.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
from tabulate import tabulate
66

7-
from investing_algorithm_framework.domain import DATETIME_FORMAT, \
8-
BacktestDateRange, TradeStatus, OrderSide, TradeRiskType, Backtest
7+
from investing_algorithm_framework.domain import DATETIME_FORMAT, Backtest, \
8+
BacktestDateRange, TradeStatus, OrderSide
99
from investing_algorithm_framework.domain.constants import \
1010
DATETIME_FORMAT_BACKTESTING
1111

@@ -144,7 +144,7 @@ def get_high_water_mark(stop_loss):
144144

145145
def get_stop_loss_price(take_profit):
146146

147-
if TradeRiskType.TRAILING.equals(take_profit["trade_risk_type"]):
147+
if take_profit["trailing"]:
148148
initial_price = take_profit["open_price"]
149149
percentage = take_profit["percentage"]
150150
initial_stop_loss_price = \
@@ -164,7 +164,7 @@ def get_stop_loss_price(take_profit):
164164
"trading_symbol": trade.trading_symbol,
165165
"status": get_status(stop_loss),
166166
"trade_id": stop_loss.trade_id,
167-
"trade_risk_type": stop_loss.trade_risk_type,
167+
"trailing": stop_loss.trailing,
168168
"percentage": stop_loss.percentage,
169169
"open_price": stop_loss.open_price,
170170
"sell_percentage": stop_loss.sell_percentage,
@@ -188,7 +188,7 @@ def get_stop_loss_price(take_profit):
188188
"trading_symbol": trade.trading_symbol,
189189
"status": get_status(stop_loss),
190190
"trade_id": stop_loss.trade_id,
191-
"trade_risk_type": stop_loss.trade_risk_type,
191+
"trailing": stop_loss.trailing,
192192
"percentage": stop_loss.percentage,
193193
"open_price": stop_loss.open_price,
194194
"sell_percentage": stop_loss.sell_percentage,
@@ -229,7 +229,7 @@ def get_stop_loss_price(take_profit):
229229
for stop_loss in selection
230230
]
231231
stop_loss_table["Type"] = [
232-
f"{stop_loss['trade_risk_type']}" for stop_loss in selection
232+
f"{stop_loss['trailing']}" for stop_loss in selection
233233
]
234234
stop_loss_table["Stop Loss (Initial Stop Loss)"] = [
235235
get_stop_loss_price(stop_loss) for stop_loss in selection
@@ -284,7 +284,7 @@ def get_sold_amount(take_profit):
284284

285285
def get_take_profit_price(take_profit):
286286

287-
if TradeRiskType.TRAILING.equals(take_profit["trade_risk_type"]):
287+
if take_profit["trailing"]:
288288
initial_price = take_profit["open_price"]
289289
percentage = take_profit["percentage"]
290290
initial_take_profit_price = \
@@ -315,7 +315,7 @@ def get_status(take_profit):
315315
"trading_symbol": trade.trading_symbol,
316316
"status": get_status(take_profit),
317317
"trade_id": take_profit.trade_id,
318-
"trade_risk_type": take_profit.trade_risk_type,
318+
"trailing": take_profit.trailing,
319319
"percentage": take_profit.percentage,
320320
"open_price": take_profit.open_price,
321321
"sell_percentage": take_profit.sell_percentage,
@@ -341,7 +341,7 @@ def get_status(take_profit):
341341
"trading_symbol": trade.trading_symbol,
342342
"status": get_status(take_profit),
343343
"trade_id": take_profit.trade_id,
344-
"trade_risk_type": take_profit.trade_risk_type,
344+
"trailing": take_profit.trailing,
345345
"percentage": take_profit.percentage,
346346
"open_price": take_profit.open_price,
347347
"sell_percentage": take_profit.sell_percentage,
@@ -383,7 +383,7 @@ def get_status(take_profit):
383383
for stop_loss in selection
384384
]
385385
take_profit_table["Type"] = [
386-
f"{stop_loss['trade_risk_type']}" for stop_loss
386+
f"{take_profit['trailing']}" for take_profit
387387
in selection
388388
]
389389
take_profit_table["Take profit (Initial Take Profit)"] = [

0 commit comments

Comments
 (0)