Overall Statistics
Total Trades
107
Average Win
0.70%
Average Loss
-0.66%
Compounding Annual Return
10.485%
Drawdown
6.400%
Expectancy
0.228
Net Profit
6.833%
Sharpe Ratio
0.862
Loss Rate
40%
Win Rate
60%
Profit-Loss Ratio
1.06
Alpha
0.083
Beta
0.014
Annual Standard Deviation
0.1
Annual Variance
0.01
Information Ratio
-0.788
Tracking Error
0.159
Treynor Ratio
6.105
Total Fees
$144.23
from datetime import datetime
import decimal
import numpy as np

class DualThrustAlgorithm(QCAlgorithm):

    def Initialize(self):
        
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
        
        self.SetStartDate(2019,1,1)
        self.SetEndDate(2019,8,30)
        self.SetBenchmark("SPY")
        self.SetCash(100000)
        equity = self.AddSecurity(SecurityType.Equity, "SPY", Resolution.Hour)
        self.syl = equity.Symbol
        
        # schedule an event to fire every trading day for a security 
        # the time rule here tells it to fire when market open 
        
        self.Schedule.On(self.DateRules.EveryDay(self.syl),self.TimeRules.AfterMarketOpen(self.syl,0),Action(self.SetSignal))
        self.selltrig = None
        self.buytrig = None
        self.currentopen = None
    
    def SetSignal(self):
        history = self.History(4, Resolution.Daily)
        k1 = 0.5
        k2 = 0.5
        self.high = []
        self.low = []
        self.close = []
        for slice in history:
            bar = slice[self.syl]
            self.high.append(bar.High)
            self.low.append(bar.Low)
            self.close.append(bar.Close)
        # Pull the open price on each trading day
        self.currentopen = self.Portfolio[self.syl].Price
        
        HH, HC, LC, LL = max(self.high), max(self.close), min(self.close), min(self.low)
        if (HH - LC) >= (HC - LL):
            signalrange = HH - LC
        else:
            signalrange = HC - LL
        
        self.selltrig = self.currentopen - decimal.Decimal(k2) * signalrange
        self.buytrig = self.currentopen + decimal.Decimal(k1) * signalrange    
    
    def OnData(self,data):
        
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''
        #db = data.bars
        
        if not data.ContainsKey(self.syl) or self.syl not in data.Keys:
            return
        
        holdings = self.Portfolio[self.syl].Quantity
        
        self.Log('Holdings: ' + str(holdings))
        if self.Portfolio[self.syl].Price >= self.buytrig:
            if holdings >= 0:
                self.SetHoldings(self.syl, 0.8)
            else:
                self.Liquidate(self.syl)
                self.SetHoldings(self.syl, 0.8)
                
        elif self.Portfolio[self.syl].Price < self.selltrig:
             if holdings >= 0:
                self.Liquidate(self.syl)
                self.SetHoldings(self.syl, -0.8)
             else:
                self.SetHoldings(self.syl, -0.8)
        self.Log(str(self.Time) )
        self.Log(str(data.Time))
        value_str = ""
        for s in data.Values:
            self.Log(type(s))  # this gives one tradebar
            self.Log(str(s.Close) + " " + str(s.Open) + " " + str(s.High) + " " + str(s.Low) + " "+ str(s.Volume))
        self.Log("open: "+ str(self.currentopen)+" buy: "+str(self.buytrig)+" sell: "+str(self.selltrig))