Overall Statistics
Total Orders
24310
Average Win
0.01%
Average Loss
-0.01%
Compounding Annual Return
350.800%
Drawdown
47.900%
Expectancy
-0.029
Net Profit
4.212%
Sharpe Ratio
498.161
Sortino Ratio
1896.866
Probabilistic Sharpe Ratio
55.296%
Loss Rate
53%
Win Rate
47%
Profit-Loss Ratio
1.07
Alpha
2134.872
Beta
6.264
Annual Standard Deviation
4.316
Annual Variance
18.626
Information Ratio
565.068
Tracking Error
3.8
Treynor Ratio
343.24
Total Fees
â‚®0.00
Estimated Strategy Capacity
â‚®1000.00
Lowest Capacity Asset
SOLUSDT 2UZ
Portfolio Turnover
1081.14%
from datetime import timedelta

from AlgorithmImports import *


class Chakh(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2024, 1, 1)
        self.SetEndDate(2024, 1, 10)

        self.SetAccountCurrency("USDT", 10000)
        self.SetBrokerageModel(BrokerageName.Bybit, AccountType.Margin)

        crypto = self.AddCrypto('SOLUSDT', Resolution.Minute, Market.Bybit)
        crypto.SetFeeModel(ConstantFeeModel(0))
        self.symbol = crypto.Symbol
        self.lotsize = crypto.SymbolProperties.LotSize

        self.take_profit = 120
        self.percentile = 0.95

        self.trade_bar_window = RollingWindow[TradeBar](60)
        self.necessary_down_window = RollingWindow[float](60)
        self.percentile_down_window = RollingWindow[float](60)

        self.Consolidate(self.symbol, timedelta(minutes=1), self.trade_bar_window_consolidation_handler)

    def OnData(self, data: Slice):
        if not self.trade_bar_window.IsReady:
            return

        # set long limit orders
        long_order_price = round(self.Securities[self.symbol].Price * (1 - self.percentile_down_window[0]), 2)
        order_properties = BybitOrderProperties()
        order_properties.TimeInForce = TimeInForce.GoodTilDate(self.Time + timedelta(minutes=2))
        size = 50 / long_order_price

        self.LimitOrder(self.symbol, size, long_order_price, 'limit long', order_properties)

    def trade_bar_window_consolidation_handler(self, bar: TradeBar):
        self.trade_bar_window.Add(bar)
        self.necessary_down_window.Add((1 - bar.Low / bar.Open))
        l = list(sorted(self.necessary_down_window))
        self.percentile_down_window.Add(l[int(self.percentile * len(l))])

    def OnOrderEvent(self, orderEvent: OrderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            return

        if orderEvent.Direction == OrderDirection.Buy:
            # set take profit via limit sell order
            size = orderEvent.FillQuantity
            take_profit_price = round(orderEvent.LimitPrice * (1 + self.percentile_down_window[0] * self.take_profit / 100), 2)
            self.LimitOrder(self.symbol, -size, take_profit_price, 'take profit long')