Created with Highcharts 12.1.2Equity19982000200220042006200820102012201420162018202020222024202650k100k150k200k250k300k350k400k450k500k550k600k
Overall Statistics
Total Orders
653
Average Win
2.08%
Average Loss
-2.04%
Compounding Annual Return
6.054%
Drawdown
20.800%
Expectancy
0.263
Start Equity
100000
End Equity
496665.83
Net Profit
396.666%
Sharpe Ratio
0.255
Sortino Ratio
0.171
Probabilistic Sharpe Ratio
0.073%
Loss Rate
37%
Win Rate
63%
Profit-Loss Ratio
1.02
Alpha
0
Beta
0
Annual Standard Deviation
0.09
Annual Variance
0.008
Information Ratio
0.505
Tracking Error
0.09
Treynor Ratio
0
Total Fees
$5071.99
Estimated Strategy Capacity
$73000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
6.54%
# https://quantpedia.com/strategies/turn-of-the-month-in-equity-indexes/
#
# Buy SPY ETF 1 day (some papers say 4 days) before the end of the month and sell the 3rd trading day of the new month at the close.
#
# Implementation changes:
#   - Trade execution is done 5 minutes before day close.

#region imports
from AlgorithmImports import *
from dateutil.relativedelta import relativedelta
#endregion

class TurnoftheMonthinEquityIndexes(QCAlgorithm):

    _ticker: str = 'SPY'

    _before_tom_offset: int = 5
    _after_tom_offset: int = 3

    _before_close_min_offset: int = 5
    
    def initialize(self) -> None:
        self.set_start_date(1998, 1, 1)
        self.set_cash(100_000)

        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
        self.settings.minimum_order_margin_portfolio_percentage = 0
        self.settings.daily_precise_end_time = True
        
        self._market: Symbol = self.add_equity(self._ticker, Resolution.MINUTE).symbol

        self.schedule.on(
            self.date_rules.month_end(self._market, self._before_tom_offset - 1),
            self.time_rules.before_market_close(self._market, self._before_close_min_offset),
            self._open_trade
        )
        self.schedule.on(
            self.date_rules.month_start(self._market, self._after_tom_offset - 1),
            self.time_rules.before_market_close(self._market, self._before_close_min_offset),
            self._close_trade
        )

    def _open_trade(self) -> None:
        if not self.portfolio[self._market].invested:
            self.set_holdings(self._market, 1.)

    def _close_trade(self) -> None:
        self.liquidate(self._market)

    def on_data(self, slice: Slice) -> None:
        pass