SymbolData.py

Created Diff never expires
41 removals
140 lines
27 additions
132 lines
Charts
Statistics
Code


##################################
##################################
#
#
# SymbolData Class
# SymbolData Class
#
#
##################################
##################################
class SymbolData():
class SymbolData():
## Constructor
## Constructor
## -----------
## -----------
def __init__(self, theSymbol, algo):
def __init__(self, theSymbol, algo):

## Algo / Symbol / Price reference
## Algo / Symbol / Price reference
self.algo = algo
self.algo = algo
self.symbol = theSymbol
self.symbol = theSymbol
self.lastDailyClose = None
self.lastDailyClose = None
self.lastClosePrice = None
self.lastClosePrice = None
## Initialize our Indicators and rolling windows
## Initialize our Indicators and rolling windows
self.ema = ExponentialMovingAverage(self.algo.dailyEMAPeriod)
self.ema = ExponentialMovingAverage(self.algo.dailyEMAPeriod)
self.momentum = MomentumPercent(self.algo.hourlyMomPeriod)
self.momentum = MomentumPercent(self.algo.hourlyMomPeriod)
self.lastDailyCloseWindow = RollingWindow[float](2)
self.lastDailyCloseWindow = RollingWindow[float](2)
self.emaWindow = RollingWindow[float](2)
self.emaWindow = RollingWindow[float](2)
## These will hold our 'messages' used in our order notes
## These will hold our 'messages' used in our order notes
self.ClosePositionMessage = ""
self.ClosePositionMessage = ""
self.OpenPositionMessage = ""
self.OpenPositionMessage = ""


## Seed Daily indicators with history.
## Seed Daily indicators with history.
## -----------------------------------
## -----------------------------------
def SeedDailyIndicators(self, dailyHistory):
def SeedDailyIndicators(self, dailyHistory):

# Loop over the history data and update our indicators
# Loop over the history data and update our indicators
if dailyHistory.empty or 'close' not in dailyHistory.columns:
if dailyHistory.empty or 'close' not in dailyHistory.columns:
# self.algo.Log(f"No Daily history for {self.symbol}")
# self.algo.Log(f"No Daily history for {self.symbol}")
return
return
else:
else:
for timeIndex, dailyBar in dailyHistory.loc[self.symbol].iterrows():
for timeIndex, dailyBar in dailyHistory.loc[self.symbol].iterrows():
if(self.ema is not None):
self.ema.Update(timeIndex, dailyBar['close'])
self.ema.Update(timeIndex, dailyBar['close'])
self.lastDailyClose = dailyBar['close']
self.lastDailyClose = dailyBar['close']
self.timeOflastDailyClose = timeIndex
self.timeOflastDailyClose = timeIndex
self.lastDailyCloseWindow.Add( dailyBar['close'] )
self.lastDailyCloseWindow.Add(dailyBar['close'])
self.emaWindow.Add( self.ema.Current.Value )
self.emaWindow.Add(self.ema.Current.Value)


## Seed intraday indicators with history
## Seed intraday indicators with history
## These indicators might be have eitehr hourly or minute resolution
## These indicators might be have eitehr hourly or minute resolution
## -----------------------------------------------------------------
## -----------------------------------------------------------------
def SeedIntradayIndicators(self, hourlyHistory=None, minuteHistory=None):
def SeedIntradayIndicators(self, hourlyHistory=None, minuteHistory=None):
# Loop over the history data and update our indicators
# Loop over the history data and update our indicators
if hourlyHistory is not None:
if hourlyHistory is not None:
if hourlyHistory.empty or 'close' not in hourlyHistory.columns:
if hourlyHistory.empty or 'close' not in hourlyHistory.columns:
self.algo.Log(f"Missing hourly history for {self.symbol}")
self.algo.Log(f"Missing hourly history for {self.symbol}")
else:
else:
for timeIndex, hourlyBar in hourlyHistory.loc[self.symbol].iterrows():
for timeIndex, hourlyBar in hourlyHistory.loc[self.symbol].iterrows():
if(self.momentum is not None):
self.momentum.Update(timeIndex, hourlyBar['close'])
self.momentum.Update(timeIndex, hourlyBar['close'])


# If you are using minuteHistory, you need to add "someIndicator" to manage it in this class (in __init__())
if minuteHistory is not None:
if minuteHistory is not None:
if minuteHistory.empty or 'close' not in minuteHistory.columns:
if minuteHistory.empty or 'close' not in minuteHistory.columns:
self.algo.Log(f"Missing minute history for {self.symbol}")
self.algo.Log(f"Missing minute history for {self.symbol}")
else:
else:
for timeIndex, hourlyBar in hourlyHistory.loc[self.symbol].iterrows():
for timeIndex, minuteBar in minuteHistory.loc[self.symbol].iterrows():
if(self.someIndicator is not None):
if self.someIndicator is not None:
self.someIndicator.Update(timeIndex, hourlyBar['close'])
self.someIndicator.Update(timeIndex, minuteBar['close'])
return
return
## Daily screening criteria. Called by the main algorithm.
## Daily screening criteria. Called by the main algorithm.
## Returns true if daily screening conditions are met.
## Returns true if daily screening conditions are met.
## Replace with your own criteria.
## Replace with your own criteria.
## -------------------------------------------------------
## -------------------------------------------------------
@property
def DailyScreeningCriteriaMet(self):
def DailyScreeningCriteriaMet(self):
## Price is above ema.
## Price is above ema.
if(self.lastDailyCloseWindow[0] > self.emaWindow[0]):
if self.lastDailyCloseWindow[0] > self.emaWindow[0]:
return True
return True
return False
return False


## Intraday screening criteria. Called by the main
## Intraday screening criteria. Called by the main
## algorithm. Returns true if entry conditions are met.
## algorithm. Returns true if entry conditions are met.
## Replace with your own criteria.
## Replace with your own criteria.
## ----------------------------------------------------
## ----------------------------------------------------
@property
def IntradayScreeningCriteriaMet(self):
def IntradayScreeningCriteriaMet(self):

## If we have positive momentum
## If we have positive momentum
if (self.momentum.Current.Value > 0):
if self.momentum.Current.Value > 0:

## Informative message that will be submitted as order notes
## Informative message that will be submitted as order notes
self.OpenPositionMessage = f"OPEN (${round(self.lastDailyCloseWindow[0],3)} > EMA: {round(self.emaWindow[0],3)})"
self.OpenPositionMessage = f"OPEN (${round(self.lastDailyCloseWindow[0],3)} > EMA: {round(self.emaWindow[0],3)})"
return True
return True
return False
return False


## Trade Exit criteria. Called by the main algorithm.
## Trade Exit criteria. Called by the main algorithm.
## Returns true if exit conditions are met.
## Returns true if exit conditions are met.
## Replace with your own criteria.
## Replace with your own criteria.
## ---------------------------------------------------
## ---------------------------------------------------
@property
def ExitCriteriaMet(self):
def ExitCriteriaMet(self):

## Exit If price is below ema
## Exit If price is below ema
if( self.lastClosePrice < self.ema.Current.Value ):
if self.lastClosePrice < self.ema.Current.Value:
self.ClosePositionMessage = f"CLOSE (${round(self.lastClosePrice,3)} < EMA: {round(self.ema.Current.Value,3)})"
self.ClosePositionMessage = f"CLOSE (${round(self.lastClosePrice,3)} < EMA: {round(self.ema.Current.Value,3)})"
return True
return True

return False
return False


## Returns true if our daily indicators are ready.
## Returns true if our daily indicators are ready.
## Called from the main algo
## Called from the main algo
## -----------------------------------------------
## -----------------------------------------------
@property
def DailyIndicatorsAreReady(self):
def DailyIndicatorsAreReady(self):
return (self.ema.IsReady and self.lastDailyCloseWindow.IsReady)
return self.ema.IsReady and self.lastDailyCloseWindow.IsReady


## Returns true if our intraday indicators are ready.
## Returns true if our intraday indicators are ready.
## Called from the main algo
## Called from the main algo
## --------------------------------------------------
## --------------------------------------------------
@property
def IntradayIndicatorsAreReady(self):
def IntradayIndicatorsAreReady(self):
return (self.momentum.IsReady)
return self.momentum.IsReady
## Called by the main algorithm right after
## Called by the main algorithm right after
## a position is opened for this symbol.
## a position is opened for this symbol.
## ----------------------------------------
## ----------------------------------------
def OnPositionOpened(self):
def OnPositionOpened(self):
## Register & warmup the indicators we need to track for exits
## Register & warmup the indicators we need to track for exits
self.algo.RegisterIndicator(self.symbol, self.ema, timedelta(1))
self.algo.RegisterIndicator(self.symbol, self.ema, timedelta(1))
self.algo.WarmUpIndicator(self.symbol, self.ema, Resolution.Daily)
self.algo.WarmUpIndicator(self.symbol, self.ema, Resolution.Daily)
## Called by the main algorithm right after
## Called by the main algorithm right after
## a position is closed for this symbol.
## a position is closed for this symbol.
## ----------------------------------------
## ----------------------------------------
def OnPositionClosed(self):
def OnPositionClosed(self):
# cleanup
# cleanup
pass
pass