| 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 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
from datetime import datetime, date, time
from datetime import timedelta
import pandas as pd
class SymbolData:
def __init__(self,algo,symbol):
self.algo = algo
self.symbol = symbol
self.openPrice = -1
self.lowestPrice = -1
self.ticket = None
self.daily = RollingWindow[TradeBar](2)
self.window = RollingWindow[TradeBar](2)
self.rsi1 = RelativeStrengthIndex( 14, MovingAverageType.Wilders)
cons1 = TradeBarConsolidator(timedelta(minutes=15))
self.algo.SubscriptionManager.AddConsolidator(symbol,cons1)
self.algo.RegisterIndicator(symbol,self.rsi1,cons1)
self.rsi2 = RelativeStrengthIndex(14, MovingAverageType.Wilders)
cons2 = TradeBarConsolidator(timedelta(minutes=2))
self.algo.SubscriptionManager.AddConsolidator(symbol,cons2)
self.algo.RegisterIndicator(symbol,self.rsi2,cons2)
# Add consolidator for obtaining previous days close
cons3 = TradeBarConsolidator(timedelta(1))
cons3.DataConsolidated += self.OnDailyData
self.algo.SubscriptionManager.AddConsolidator(symbol,cons3)
# Add daily bar to daily rolling window
def OnDailyData(self, sender, bar):
self.daily.Add(bar)
def IsReady(self):
return self.rsi1.IsReady and self.rsi2.IsReady
class TradeStrategyTest(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021,3, 1) #Set Start Date
self.SetEndDate(2021,7,1) #Set End Date
self.SetCash(30000) #Set Strategy Cash
self.SetWarmUp(210)
self.expiry = self.Time
# Set TimeZone
self.SetTimeZone("America/New_York")
# Add Equities
tickers = ['OCGN']
# Add Equities from .csv file - UNDER TESTING NOT COMPLETE!!!!
# Create a dataframe from csv
#self.Equities = pd.read_csv('test.csv', delimiter=',')
self.dataBySymbol = {}
self.Equities = []
# Set resoltuion for Equity data
for Symbol in tickers:
symbol = self.AddEquity(Symbol, Resolution.Minute).Symbol
self.dataBySymbol[symbol] = SymbolData(self,symbol)
self.Equities.append(symbol)
# Set Fee Model
for Symbol in self.Equities:
self.Securities[Symbol].FeeModel = ConstantFeeModel(1.00)
def OnData(self, data):
if self.IsWarmingUp:return
# Loop through our equities
for Symbol in self.Equities:
if data.ContainsKey(Symbol) and data[Symbol] is not None and self.dataBySymbol[Symbol].IsReady() :
# Set local variables
close = data.Bars[Symbol].Close
quantity = self.CalculateOrderQuantity(Symbol,1*0.2)
AskPrice = self.Securities[Symbol].AskPrice
BidPrice = self.Securities[Symbol].BidPrice
Spread = (AskPrice - BidPrice)
RSI1 = self.dataBySymbol[Symbol].rsi1.Current.Value
RSI2 = self.dataBySymbol[Symbol].rsi2.Current.Value
# Setup Open and Close Prices and Bars
self.window.Add(data[Symbol])
if not (self.window.IsReady and self.daily.IsReady): return
previous_bar_close = self.window[0].Close
previous_day_close = self.daily[1].Close
change_from_close = (((previous_bar_close - previous_day_close) / previous_bar_close) * 100)
#Obtain Low of Day and Update
bar = data[Symbol]
if not bar.IsFillForward and self.dataBySymbol[Symbol].lowestPrice < 0:
self.dataBySymbol[Symbol].openPrice = bar.Open
self.dataBySymbol[Symbol].lowestPrice = bar.Low
if self.dataBySymbol[Symbol].lowestPrice < 0:
return
price = bar.Low
if price < self.dataBySymbol[Symbol].lowestPrice: # If we observe a new low
self.dataBySymbol[Symbol].lowestPrice = price
# IMPORTANT!!! Time variables to set open/close times and compare them to current time.
# Convert times to variables (necessary for time comparison)
currentTime = self.Time
openTime = time(9,30)
closeTime = time(12,0)
# Convert string to format that can be compared (comparison does not work if you do not do this)
# These comparisons are to test it works, before implementing them in the # Buy Conditions function below
# It is OK to comment them out here, as they are just for testing. Real function below.
#currentTime.strftime('%H%M') >= openTime.strftime('%H%M')
#currentTime.strftime('%H%M') <= closeTime.strftime('%H%M')
# Buy Conditions
if not self.Portfolio[Symbol].Invested and self.dataBySymbol[Symbol].ticket is None and (currentTime.strftime('%H%M') >= openTime.strftime('%H%M') and currentTime.strftime('%H%M') <= closeTime.strftime('%H%M')):
#
# If buy conditions are satisfied then place MarketOrder
if ((RSI1 <=70 and RSI1 >=20) and (RSI2 >0 and RSI2 <=25) and (Spread >=0 and Spread <=0.01) and (change_from_close >=-11 and change_from_close <=-4) and (previous_bar_close <= self.dataBySymbol[Symbol].lowestPrice)):
self.dataBySymbol[Symbol].ticket= self.MarketOrder(Symbol, quantity, tag ="Market Buy") and self.Debug(f"RSI1 Value: {RSI1}, RSI2 Value: {RSI2}, Change from close: {change_from_close}, Spread: {Spread}, Prev Bar Close: {previous_bar_close}, Lowest Price: {self.dataBySymbol[Symbol].lowestPrice}, Previous day close: {previous_day_close}, Time: {self.Time}")
# Place Profit take and Stop Loss orders then reset to None
self.LimitOrder(Symbol, -quantity, close * 1.03, tag = "Profit Take")
self.StopMarketOrder(Symbol, -quantity, close * 0.99, tag = "Stopped Out")
self.dataBySymbol[Symbol].ticket = None
else:
# Close position if open for more than 15 minutes and set ticket to None
if self.dataBySymbol[Symbol].ticket is not None and (self.Time > self.ticket.Time + timedelta(minutes = 15)):
self.Liquidate(Symbol)
self.dataBySymbol[Symbol].ticket = None
# Cancel remaining order if limit order or stop loss order is executed
def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if order.Status == OrderStatus.Filled:
if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket:
self.Transactions.CancelOpenOrders(order.Symbol)
if order.Status == OrderStatus.Canceled:
self.Log(str(orderEvent))
#Reset Daily :Pointer
def OnEndOfDay(self, symbol):
for Symbol in self.Equities:
self.dataBySymbol[Symbol].lowestPrice = -1