Overall Statistics
Total Orders
2048
Average Win
12.87%
Average Loss
-3.36%
Compounding Annual Return
65657410.138%
Drawdown
21.800%
Expectancy
0.611
Start Equity
100000
End Equity
193588.6
Net Profit
93.589%
Sharpe Ratio
29256.739
Sortino Ratio
132706.05
Probabilistic Sharpe Ratio
99.702%
Loss Rate
67%
Win Rate
33%
Profit-Loss Ratio
3.83
Alpha
42982.288
Beta
23.695
Annual Standard Deviation
1.47
Annual Variance
2.16
Information Ratio
30355.69
Tracking Error
1.417
Treynor Ratio
1814.722
Total Fees
$64.50
Estimated Strategy Capacity
$0
Lowest Capacity Asset
ES YJHOAMPYKQGX
Portfolio Turnover
357.24%
# region imports
from AlgorithmImports import *
# endregion

class TerminalLinkFutureTickAlgorithm(QCAlgorithm):
    def initialize(self):
        self.set_start_date(2024, 6, 1)
        self.set_cash(100000)
        
        # Set the default order properties to use Terminal Link order properties
        # which allow additional settings, such as VWAP strategy
        # See https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/brokerages/supported-models/terminal-link#03-Orders
        # It doesn't affect backtesting
        self.default_order_properties = TerminalLinkOrderProperties()
        self.default_order_properties.time_in_force = TimeInForce.GOOD_TIL_CANCELED
        self.default_order_properties.strategy = TerminalLinkOrderProperties.StrategyParameters(
            "VWAP",
            [
                TerminalLinkOrderProperties.StrategyField("09:30:00"),
                TerminalLinkOrderProperties.StrategyField("10:30:00"),
                TerminalLinkOrderProperties.StrategyField(),
                TerminalLinkOrderProperties.StrategyField()
            ]
        )

        # Add the futures continuous contract with TICK resolution
        self.future = self.add_future("ES", Resolution.TICK, extended_market_hours=True)

        # Create a rolling window of 100 ticks 
        self.window = RollingWindow[Tick](100)

    def on_data(self, data: Slice):
        # Update the rolling window with the ticks in the Slice object
        # The Slice has a collection of Tick objects
        [self.window.add(tick) for tick in data.ticks.get(self.future.symbol, [])]            
        if not self.window.is_ready:
            return
        
        # RollingWindow is an array of a fixed-size that holds trailing data. 
        # Index 0 refers to the most recent item in the window 
        # and the largest index refers to the last item in the window.
        first = self.window[self.window.count-1].last_price
        last = self.window[0].last_price
        holdings = self.portfolio[self.future.mapped]

        # We open a new position when the price moves $1
        # Note we use `mapped` which represents the current contract that
        # the continuous contract refers to, we cannot use self.future.symbol
        if not holdings.is_long and last > first + 1:
            self.market_order(self.future.mapped, 1, tag=f'buy: {last} > {first}')
        if not holdings.is_short and last < first - 1:
            self.market_order(self.future.mapped, 1, tag=f'sell: {last} < {first}')