Overall Statistics
Total Orders
1324
Average Win
0.15%
Average Loss
-0.29%
Compounding Annual Return
-57.022%
Drawdown
20.600%
Expectancy
-0.066
Start Equity
100000
End Equity
88323.33
Net Profit
-11.677%
Sharpe Ratio
-2.051
Sortino Ratio
-2.866
Probabilistic Sharpe Ratio
6.431%
Loss Rate
38%
Win Rate
62%
Profit-Loss Ratio
0.52
Alpha
-0.457
Beta
-1.647
Annual Standard Deviation
0.238
Annual Variance
0.056
Information Ratio
-1.583
Tracking Error
0.32
Treynor Ratio
0.296
Total Fees
$4926.31
Estimated Strategy Capacity
$630000.00
Lowest Capacity Asset
UVXY V0H08FY38ZFP
Portfolio Turnover
374.85%
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *

class SymbolData:
    
        def __init__(self, symbol, k1, k2, range_period, consolidator_resolution):

            self.symbol = symbol
            self.range_window = RollingWindow[TradeBar](range_period)
            self.consolidator = TradeBarConsolidator(consolidator_resolution)

            def on_data_consolidated(sender, consolidated):
\
                self.range_window.add(consolidated)

                if self.range_window.is_ready:
                    hh = max([x.high for x in self.range_window])
                    hc = max([x.close for x in self.range_window])
                    lc = min([x.close for x in self.range_window])
                    ll = min([x.low for x in self.range_window])

                    range = max([hh - lc, hc - ll])
                    self.upper_line = consolidated.close + k1 * range
                    self.lower_line = consolidated.close - k2 * range

            # event fired at new consolidated trade bar
            self.consolidator.data_consolidated += on_data_consolidated

        # Returns the interior consolidator
        def get_consolidator(self):
            return self.consolidator

        @property
        def is_ready(self):
            return self.range_window.is_ready
#region imports
from AlgorithmImports import *
#endregion
from AlgorithmImports import *
from SymbolData import *

# Your New Python File
class DualThrustAlphaModel(AlphaModel):

    def __init__(self,
                 k1,
                 k2,
                 range_period,
                 resolution = Resolution.HOUR,
                 bars_to_consolidate = 1):
        '''Initializes a new instance of the class
        Args:
            k1: Coefficient for upper band
            k2: Coefficient for lower band
            range_period: Amount of last bars to calculate the range
            resolution: The resolution of data sent into the EMA indicators
            bars_to_consolidate: If we want alpha to work on trade bars whose length is different
                from the standard resolution - 1m 1h etc. - we need to pass this parameters along
                with proper data resolution'''

        # coefficient that used to determine upper and lower borders of a breakout channel
        self.k1 = k1
        self.k2 = k2

        # period the range is calculated over
        self.range_period = range_period

        # initialize with empty dict.
        self._symbol_data_by_symbol = dict()

        # time for bars we make the calculations on
        resolution_in_time_span =  Extensions.to_time_span(resolution)
        self.consolidator_time_span = Time.multiply(resolution_in_time_span, bars_to_consolidate)

        # in 5 days after emission an insight is to be considered expired
        self.period = timedelta(5)

    def update(self, algorithm, data):
        insights = []

        for symbol, symbol_data in self._symbol_data_by_symbol.items():
            if not symbol_data.is_ready:
                continue

            holding = algorithm.portfolio[symbol]
            price = algorithm.securities[symbol].price

            # buying condition
            # - (1) price is above upper line
            # - (2) and we are not long. this is a first time we crossed the line lately
            if price > symbol_data.upper_line and not holding.is_long:
                insight_close_time_utc = algorithm.utc_time + self.period
                insights.append(Insight.price(symbol, insight_close_time_utc, InsightDirection.UP))

            # selling condition
            # - (1) price is lower that lower line
            # - (2) and we are not short. this is a first time we crossed the line lately
            if price < symbol_data.lower_line and not holding.is_short:
                insight_close_time_utc = algorithm.utc_time + self.period
                insights.append(Insight.price(symbol, insight_close_time_utc, InsightDirection.DOWN))

        return insights

    def on_securities_changed(self, algorithm, changes):
        # added
        for symbol in [x.symbol for x in changes.added_securities]:
            if symbol not in self._symbol_data_by_symbol:
                # add symbol/symbol_data pair to collection
                symbol_data = self.SymbolData(symbol, self.k1, self.k2, self.range_period, self.consolidator_time_span)
                self._symbol_data_by_symbol[symbol] = symbol_data
                # register consolidator
                algorithm.subscription_manager.add_consolidator(symbol, symbol_data.get_consolidator())

        # removed
        for symbol in [x.symbol for x in changes.removed_securities]:
            symbol_data = self._symbol_data_by_symbol.pop(symbol, None)
            if symbol_data is None:
                algorithm.error("Unable to remove data from collection: DualThrustAlphaModel")
            else:
                # unsubscribe consolidator from data updates
                algorithm.subscription_manager.remove_consolidator(symbol, symbol_data.get_consolidator())
from AlgorithmImports import *
from VIXAlpha import *
from SymbolData import *

class SELLPUTFRAMEWORK(QCAlgorithm):

    def initialize(self):

        # -- STRATEGY INPUT PARAMETERS --
        self.range_period = 22
        self.bbl = 20
        self.lb = 50
        self.ph = 0.85
        self.mult = 2.0
        self.consolidator_bars = 20

        # set leverage
        self.leverage = 3
        self.yoy_return = 0.6

        # Settings
        self.universe_settings.resolution = Resolution.MINUTE
        self.set_start_date(2024,4,1)
        self.set_cash(100000)

        # Warming up
        resolution_in_time_span =  Extensions.to_time_span(self.universe_settings.resolution)
        warm_up_time_span = Time.multiply(resolution_in_time_span, self.consolidator_bars)
        self.set_warm_up(warm_up_time_span)

        # Universe Selection
        tickers = ['TQQQ', 'SQQQ', 'UVXY']
        symbols = [ Symbol.create(ticker, SecurityType.EQUITY, Market.USA) for ticker in tickers]
        self.set_universe_selection(ManualUniverseSelectionModel(symbols))

        # Alpha Model
        self.set_alpha(ConstantAlphaModel(InsightType.PRICE, InsightDirection.UP, timedelta(minutes = 20), 0.025, None))

        ## Portfolio Construction
        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(Resolution.DAILY))

        ## Execution
        self.set_execution(ImmediateExecutionModel())

        ## Risk Management
        self.set_risk_management(MaximumDrawdownPercentPerSecurity(0.01))


    def on_order_event(self, order_event):
        if order_event.status == OrderStatus.FILLED:
            self.debug("Purchased Stock: {0}".format(order_event.symbol))