Overall Statistics
Total Orders
2420
Average Win
0.93%
Average Loss
-0.38%
Compounding Annual Return
9.178%
Drawdown
26.100%
Expectancy
0.148
Start Equity
100000.00
End Equity
185702.09
Net Profit
85.702%
Sharpe Ratio
0.329
Sortino Ratio
0.389
Probabilistic Sharpe Ratio
6.807%
Loss Rate
66%
Win Rate
34%
Profit-Loss Ratio
2.41
Alpha
0.039
Beta
0.003
Annual Standard Deviation
0.119
Annual Variance
0.014
Information Ratio
-0.245
Tracking Error
0.203
Treynor Ratio
13.798
Total Fees
$0.00
Estimated Strategy Capacity
$87000.00
Lowest Capacity Asset
BTCUSD E3
Portfolio Turnover
93.77%
Drawdown Recovery
647
# region imports
from AlgorithmImports import *
# endregion

class HyperActiveAsparagusBarracuda(QCAlgorithm):

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

        self.set_time_zone('UTC')

        fast_period: int = 12
        slow_period: int = 26
        crossover: int = 9

        self._traded_asset: Symbol = self.add_crypto('BTCUSD', Resolution.HOUR, market=Market.BITFINEX).symbol

        self._daily_macd: MovingAverageConvergenceDivergence = MovingAverageConvergenceDivergence(fast_period, slow_period, crossover, MovingAverageType.EXPONENTIAL)
        self._hour_macd: MovingAverageConvergenceDivergence = self.macd(self._traded_asset, fast_period, slow_period, crossover, MovingAverageType.EXPONENTIAL, Resolution.HOUR)

        self._daily_signal_flag: bool = False
        self._update_flag: bool = False
        
        # Update daily indicator at UTC+4 according to documentation
        self.schedule.on(
            self.date_rules.every_day(),
            self.time_rules.at(4,0),
            self._update
        )

        self.schedule.on(
            self.date_rules.every_day(),
            self.time_rules.at(0,0),
            self._rebalance
        )

    def on_data(self, slice: Slice) -> None:
        # Update MACD indicator daily
        if self._update_flag:
            self._update_flag = False
            if slice.bars.contains_key(self._traded_asset):
                bar = slice.bars[self._traded_asset]
                self._daily_macd.update(bar.end_time, bar.close)

        if self.portfolio.invested:
            # Liquidate at first negative hour candle
            if slice[self._traded_asset].close < slice[self._traded_asset].open:
                self.liquidate()

        if self._daily_signal_flag:
            # Evaluate hourly signal
            if (self._hour_macd.current.value > self._hour_macd.signal.current.value and
                self._hour_macd.previous.value <= self._hour_macd.signal.previous.value):
                if not self.portfolio.invested:
                    self.set_holdings(self._traded_asset, 1)
            
    def _update(self) -> None:
        self._update_flag = True

    def _rebalance(self) -> None:
        # Evaluate daily signal
        if self._daily_macd.is_ready:
            self._daily_signal_flag = self._daily_macd.current.value > self._daily_macd.signal.current.value