Path: blob/master/src/strategies/BaseStrategy.py
298 views
import logging1import time2from datetime import datetime34from models.ProductType import ProductType5from core.Quotes import Quotes6from trademgmt.TradeManager import TradeManager78from utils.Utils import Utils910class BaseStrategy:11def __init__(self, name):12# NOTE: All the below properties should be set by the Derived Class (Specific to each strategy)13self.name = name # strategy name14self.enabled = True # Strategy will be run only when it is enabled15self.productType = ProductType.MIS # MIS/NRML/CNC etc16self.symbols = [] # List of stocks to be traded under this strategy17self.slPercentage = 018self.targetPercentage = 019self.startTimestamp = Utils.getMarketStartTime() # When to start the strategy. Default is Market start time20self.stopTimestamp = None # This is not square off timestamp. This is the timestamp after which no new trades will be placed under this strategy but existing trades continue to be active.21self.squareOffTimestamp = None # Square off time22self.capital = 10000 # Capital to trade (This is the margin you allocate from your broker account for this strategy)23self.leverage = 1 # 2x, 3x Etc24self.maxTradesPerDay = 1 # Max number of trades per day under this strategy25self.isFnO = False # Does this strategy trade in FnO or not26self.capitalPerSet = 0 # Applicable if isFnO is True (Set means 1CE/1PE or 2CE/2PE etc based on your strategy logic)27# Register strategy with trade manager28TradeManager.registerStrategy(self)29# Load all trades of this strategy into self.trades on restart of app30self.trades = TradeManager.getAllTradesByStrategy(self.name)3132def getName(self):33return self.name3435def isEnabled(self):36return self.enabled3738def setDisabled(self):39self.enabled = False4041def process(self):42# Implementation is specific to each strategy - To defined in derived class43logging.info("BaseStrategy process is called.")44pass4546def calculateCapitalPerTrade(self):47leverage = self.leverage if self.leverage > 0 else 148capitalPerTrade = int(self.capital * leverage / self.maxTradesPerDay)49return capitalPerTrade5051def calculateLotsPerTrade(self):52if self.isFnO == False:53return 054# Applicable only for fno55return int(self.capital / self.capitalPerSet)5657def canTradeToday(self):58# Derived class should override the logic if the strategy to be traded only on specific days of the week59return True6061def run(self):62# NOTE: This should not be overriden in Derived class63if self.enabled == False:64logging.warn("%s: Not going to run strategy as its not enabled.", self.getName())65return6667if Utils.isMarketClosedForTheDay():68logging.warn("%s: Not going to run strategy as market is closed.", self.getName())69return7071now = datetime.now()72if now < Utils.getMarketStartTime():73Utils.waitTillMarketOpens(self.getName())7475if self.canTradeToday() == False:76logging.warn("%s: Not going to run strategy as it cannot be traded today.", self.getName())77return7879now = datetime.now()80if now < self.startTimestamp:81waitSeconds = Utils.getEpoch(self.startTimestamp) - Utils.getEpoch(now)82logging.info("%s: Waiting for %d seconds till startegy start timestamp reaches...", self.getName(), waitSeconds)83if waitSeconds > 0:84time.sleep(waitSeconds)8586# Run in an loop and keep processing87while True:88if Utils.isMarketClosedForTheDay():89logging.warn("%s: Exiting the strategy as market closed.", self.getName())90break9192# Derived class specific implementation will be called when process() is called93self.process()9495# Sleep and wake up on every 30th second96now = datetime.now()97waitSeconds = 30 - (now.second % 30)98time.sleep(waitSeconds)99100def shouldPlaceTrade(self, trade, tick):101# Each strategy should call this function from its own shouldPlaceTrade() method before working on its own logic102if trade == None:103return False104if trade.qty == 0:105TradeManager.disableTrade(trade, 'InvalidQuantity')106return False107108now = datetime.now()109if now > self.stopTimestamp:110TradeManager.disableTrade(trade, 'NoNewTradesCutOffTimeReached')111return False112113numOfTradesPlaced = TradeManager.getNumberOfTradesPlacedByStrategy(self.getName())114if numOfTradesPlaced >= self.maxTradesPerDay:115TradeManager.disableTrade(trade, 'MaxTradesPerDayReached')116return False117118return True119120def addTradeToList(self, trade):121if trade != None:122self.trades.append(trade)123124def getQuote(self, tradingSymbol):125return Quotes.getQuote(tradingSymbol, self.isFnO)126127def getTrailingSL(self, trade):128return 0129130