Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-0.978
Tracking Error
0.275
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
from AlgorithmImports import *

class PriceActionAlpha(AlphaModel):
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.btc = symbol

        self.hour = -1
        self.selltrig = None
        self.buytrig = None
        self.currentopen = None

        self.consolidator = TradeBarConsolidator(timedelta(1))
        self.consolidator.DataConsolidated += self.OnConsolidated
        self.window = RollingWindow[TradeBar](4)

        history = algorithm.History[TradeBar](self.btc, 4*24*60, Resolution.Minute)
        for bar in history:
            self.consolidator.Update(bar)

        algorithm.SubscriptionManager.AddConsolidator(self.btc, self.consolidator)

    def OnConsolidated(self, sender, bar):
        self.window.Add(bar)
        self.currentopen = bar.Open

        if not self.window.IsReady: return

        df = self.algorithm.PandasConverter.GetDataFrame[TradeBar](self.window)    
        k1 = 0.5
        k2 = 0.5
        
        HH, HC, LC, LL = max(df['high']), max(df['close']), min(df['close']), min(df['low'])
        if (HH - LC) >= (HC - LL):
            signalrange = HH - LC
        else:
            signalrange = HC - LL
        
        self.selltrig = self.currentopen - k2 * signalrange
        self.buytrig = self.currentopen + k1 * signalrange    
    
    def Update(self, algorithm, data):        
        # We only use hourly signals
        if not data.ContainsKey(self.btc) or not self.window.IsReady:
            return []

        if self.hour == algorithm.Time.hour:
            return []
        self.hour = algorithm.Time.hour
        
        price = data[self.btc].Price
        
        if algorithm.LiveMode:
            algorithm.Log(f'Buy Trigger {self.buytrig} > Price {price} > {self.selltrig}')
        
        if price >= self.buytrig:
            return [Insight(self.btc, timedelta(days=365), InsightType.Price, InsightDirection.Up)]
        elif price < self.selltrig:
            algorithm.Insights.Cancel([self.btc])
        
        return []
from AlgorithmImports import *
from alpha import PriceActionAlpha

# BTCUSD Long Only Dual Thrust Algorithm 
# Originated by Michael Vitucci
class DualThrustAlgorithm(QCAlgorithm):
    def UniverseSelectionFilter(self, crypto_coarse: List[CryptoCoarseFundamental]) -> List[Symbol]:
        for cf in crypto_coarse: print(cf)
        pool=[cf.Symbol for cf in crypto_coarse if str(cf.Symbol).endswith('BUSD') and cf.Volume >= 100 and cf.VolumeInUsd > 10000 ]
        return pool
     

    def Initialize(self):
        self.SetStartDate(2023, 1, 1)
        self.SetEndDate(2023, 10, 1)
        self.SetCash(10000)
        self.SetBrokerageModel(BrokerageName.Binance, AccountType.Cash)
        self.AddUniverse(CryptoCoarseFundamentalUniverse(Market.Binance, self.UniverseSettings, self.UniverseSelectionFilter))


    def OnData(self, data):
        if not self.Portfolio.Invested:
            for symbol in self.ActiveSecurities.Keys:
                print(symbol)
                self.SetHoldings(symbol, 1 / len(self.ActiveSecurities.Keys))

    def FineSelectionFunction(self, fine):
        # Calculate the 5-day momentum
        momentum = {}
        for i in fine:
            history = self.History([i.Symbol], timedelta(days=5), Resolution.Daily)
            if not history.empty:
                close = history.loc[str(i.Symbol)]['close']
                i.momentum = (close[0]-close[-1])/close[-1]
                momentum[i.Symbol] = i.momentum

        # Sort by momentum and take the top 10
        sorted_by_momentum = sorted(momentum.items(), key=lambda x: x[1], reverse=True)
        self.long = [i[0] for i in sorted_by_momentum[:10]]

        return self.long