Overall Statistics
Total Orders
12638
Average Win
0.25%
Average Loss
-0.28%
Compounding Annual Return
0.762%
Drawdown
34.700%
Expectancy
0.014
Start Equity
100000
End Equity
121218.61
Net Profit
21.219%
Sharpe Ratio
-0.283
Sortino Ratio
-0.289
Probabilistic Sharpe Ratio
0.000%
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
0.90
Alpha
-0.021
Beta
0.128
Annual Standard Deviation
0.056
Annual Variance
0.003
Information Ratio
-0.38
Tracking Error
0.149
Treynor Ratio
-0.125
Total Fees
$0.00
Estimated Strategy Capacity
$19000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
136.05%
# https://quantpedia.com/strategies/lunch-effect-in-the-u-s-stock-market-indices/
# 
# The investment universe for this strategy is centered on the SPDR S&P 500 ETF Trust (SPY), which represents the S&P 500 Index. This ETF is chosen due to its 
# high liquidity and broader U.S. stock market representation. The strategy can also be applied to other trading vehicles, such as near-term futures on the S&P 500 
# Index (e.g., S&P 500 E-mini Futures) or CFDs on SPY. (The selection of SPY is based on its ability to capture the overall market movements and its suitability for
# intraday and overnight trading strategies.)
# (You can get data for your backtesting needs from Yahoo Finance and/or Finram.)
# The strategy employs specific time-based trading rules derived from the research paper’s findings on the Lunch Effect and Overnight Anomaly. No additional technical 
# indicators are used; the approach is purely time-based.
# Once again, rules overview:
# 1. At 11:00 AM ET, enter a short position on SPY.
# 2. At noon ET: reverse; hence, cover the short position and enter a long position on SPY.
# 3. At 2:00 PM ET, exit the extended position.
# This is an intraday strategy with no overnight holding and involves one (100 %) asset, so it is fully weighted in that proportion of total capital.
#
# QC implementation changes:
#   - Only long position at 12:00 PM ET is held until 14:00 PM ET. Short position is not traded.
#   - No trading fees are applied and mid price execution is enforced to test out strategy's theoretical performance.

# region imports
from AlgorithmImports import *
# endregion

class LunchEffectInTheUSStockMarketIndices(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2000, 1, 1)
        self.set_cash(100_000)

        self._traded_asset: Symbol = self.add_equity('SPY', Resolution.MINUTE).symbol
        self.securities[self._traded_asset].set_fee_model(ConstantFeeModel(0))
        self.securities[self._traded_asset].set_fill_model(MidPriceFillModel())

        self._trading_hours: List[int] = [12, 14]
       
    def on_data(self, slice: Slice) -> None:
        if slice.contains_key(self._traded_asset) and slice[self._traded_asset]:
            if self.time.hour == self._trading_hours[0]:
                if not self.portfolio[self._traded_asset].invested:
                    self.set_holdings(self._traded_asset, 1)

            if self.time.hour == self._trading_hours[1]:
                if self.portfolio[self._traded_asset].invested:
                    self.liquidate()

class MidPriceFillModel(FillModel):
    def market_fill(self, asset, order) -> OrderEvent:
        mid_price: float = (asset.bid_price + asset.ask_price) / 2.
        fill = OrderEvent(
            orderId=order.Id, symbol=order.Symbol, utcTime=order.Time, status=OrderStatus.Filled,
            direction=order.Direction,
            fillPrice=mid_price, fillQuantity=order.Quantity, orderFee=OrderFee.Zero
        )

        return fill