Overall Statistics
Total Trades
71
Average Win
1.74%
Average Loss
-0.25%
Compounding Annual Return
14057.506%
Drawdown
2.100%
Expectancy
0.819
Net Profit
7.993%
Sharpe Ratio
155.692
Probabilistic Sharpe Ratio
99.979%
Loss Rate
77%
Win Rate
23%
Profit-Loss Ratio
6.96
Alpha
69.851
Beta
-2.08
Annual Standard Deviation
0.461
Annual Variance
0.212
Information Ratio
106.805
Tracking Error
0.68
Treynor Ratio
-34.492
Total Fees
$211.82
Estimated Strategy Capacity
$15000000.00
Lowest Capacity Asset
MSFT R735QTJ8XC9X
from AlgorithmImports import *


class BasicAlgo(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2020, 2, 19)  # Set Start Date
        self.SetEndDate(2020, 2, 24)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash
        self.symbol = self.AddEquity("MSFT", Resolution.Second).Symbol

        self.td = float(self.GetParameter("tick_amount"))
        self.window_size_p = int(float(self.GetParameter("window_size_p")))
        self.window_size_n = int(float(self.GetParameter("window_size_n")))
        self.prob_threshold = float(self.GetParameter("pt"))
        renkoClose = ClassicRenkoConsolidator(self.td)
        renkoClose.DataConsolidated += self.HandleRenkoClose

        self.SubscriptionManager.AddConsolidator(self.symbol, renkoClose)

        self.next_positive_prob = 0 
        self.next_negative_prob = 0
        self.next_positive_prob_1 = 0 
        self.next_negative_prob_1 = 0
        self.next_positive_prob_2 = 0 
        self.next_negative_prob_2 = 0
        self.tick_seq = []
        self.index_list = []
        self.cash_rate = 0.005
        self.leverage_rate = .0075
        self.short_rate = 0.0025
        self.leverage_costs = 0
        self.cash_interests = 0
        self.short_costs = 0
        self.max_leverage = 2

        self.window_total_p = 0
        self.window_total_n = 0
        self.positive_ticks = 0
        self.next_positive = 0
        self.negative_ticks = 0
        self.next_negative = 0

        self.window_total_2_p = 0
        self.window_total_2_n = 0
        self.positive_ticks_2 = 0
        self.next_positive_2 = 0
        self.negative_ticks_2 = 0
        self.next_negative_2 = 0

    def OnData(self, data):
        self.next_positive_prob = self.next_positive_prob_1
        self.next_negative_prob = self.next_negative_prob_1

        if not self.Portfolio.Invested:
            if self.next_negative_prob > self.prob_threshold:
                if sum(self.tick_seq[-(self.window_size_n)+1:]) == -self.window_size_n+1:
                    self.SetHoldings(self.symbol,-1)                           
                    self.Debug('Shorted at ' + str(data[self.symbol].Close))
            if self.next_positive_prob > self.prob_threshold:
                if sum(self.tick_seq[-(self.window_size_p)+1:]) == self.window_size_p-1:
                    self.SetHoldings(self.symbol,1)
                    self.Debug('Bought at ' + str(data[self.symbol].Close))

        if self.Portfolio[self.symbol].IsShort:
            if sum(self.tick_seq[-(self.window_size_n)+1:]) == self.window_size_n-1:
                self.SetHoldings(self.symbol, 0)
                self.Debug('Stoped short at '+ str(data[self.symbol].Close))
        if self.Portfolio[self.symbol].IsLong:
            if sum(self.tick_seq[-(self.window_size_p)+1:]) == -self.window_size_p+1:
                self.Liquidate()
                self.Debug('Liqudated at '+ str(data[self.symbol].Close))

    def HandleRenkoClose(self, sender, data):
        self.Debug(f"CLOSE - {data.Time} - {data.Open} {data.Close} {self.Securities[self.symbol].Price}")
        if data.Open < data.Close:
            self.tick_seq.append(1)
        else:
            self.tick_seq.append(-1)

        self.Get_Probabilities()

    def Get_Probabilities(self):

        if len(self.tick_seq) == 0: return
        self.tick_idx = [i for i in range(len(self.tick_seq))]

        for i in range(self.window_size_p ,len(self.tick_seq)+1):
            self.window_total_p = np.sum( self.tick_seq[i-self.window_size_p:i-1] )
            if self.window_total_p == self.window_size_p-1:
                self.positive_ticks += 1
                if self.tick_seq[i-1] == 1:
                    self.next_positive += 1
        for i in range(self.window_size_n ,len(self.tick_seq)+1):
            self.window_total_n = np.sum( self.tick_seq[i-self.window_size_n:i-1] )
            if -self.window_total_n == self.window_size_n-1:
                self.negative_ticks += 1
                if self.tick_seq[i-1] == -1:
                    self.next_negative += 1
                    
        if self.positive_ticks == 0: self.next_positive_prob_1 = 0
        else: self.next_positive_prob_1 = self.next_positive/self.positive_ticks
        if self.negative_ticks == 0: self.next_negative_prob_1=0
        else: self.next_negative_prob_1 = self.next_negative /self.negative_ticks
        self.Debug('Renko N. Positive probability: ' + str(self.next_positive_prob_1) +' negative probability ' + str(self.next_negative_prob_1))