Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sreenivasdoosa
GitHub Repository: sreenivasdoosa/sdoosa-algo-trade-python
Path: blob/master/src/strategies/BaseStrategy.py
298 views
1
import logging
2
import time
3
from datetime import datetime
4
5
from models.ProductType import ProductType
6
from core.Quotes import Quotes
7
from trademgmt.TradeManager import TradeManager
8
9
from utils.Utils import Utils
10
11
class BaseStrategy:
12
def __init__(self, name):
13
# NOTE: All the below properties should be set by the Derived Class (Specific to each strategy)
14
self.name = name # strategy name
15
self.enabled = True # Strategy will be run only when it is enabled
16
self.productType = ProductType.MIS # MIS/NRML/CNC etc
17
self.symbols = [] # List of stocks to be traded under this strategy
18
self.slPercentage = 0
19
self.targetPercentage = 0
20
self.startTimestamp = Utils.getMarketStartTime() # When to start the strategy. Default is Market start time
21
self.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.
22
self.squareOffTimestamp = None # Square off time
23
self.capital = 10000 # Capital to trade (This is the margin you allocate from your broker account for this strategy)
24
self.leverage = 1 # 2x, 3x Etc
25
self.maxTradesPerDay = 1 # Max number of trades per day under this strategy
26
self.isFnO = False # Does this strategy trade in FnO or not
27
self.capitalPerSet = 0 # Applicable if isFnO is True (Set means 1CE/1PE or 2CE/2PE etc based on your strategy logic)
28
# Register strategy with trade manager
29
TradeManager.registerStrategy(self)
30
# Load all trades of this strategy into self.trades on restart of app
31
self.trades = TradeManager.getAllTradesByStrategy(self.name)
32
33
def getName(self):
34
return self.name
35
36
def isEnabled(self):
37
return self.enabled
38
39
def setDisabled(self):
40
self.enabled = False
41
42
def process(self):
43
# Implementation is specific to each strategy - To defined in derived class
44
logging.info("BaseStrategy process is called.")
45
pass
46
47
def calculateCapitalPerTrade(self):
48
leverage = self.leverage if self.leverage > 0 else 1
49
capitalPerTrade = int(self.capital * leverage / self.maxTradesPerDay)
50
return capitalPerTrade
51
52
def calculateLotsPerTrade(self):
53
if self.isFnO == False:
54
return 0
55
# Applicable only for fno
56
return int(self.capital / self.capitalPerSet)
57
58
def canTradeToday(self):
59
# Derived class should override the logic if the strategy to be traded only on specific days of the week
60
return True
61
62
def run(self):
63
# NOTE: This should not be overriden in Derived class
64
if self.enabled == False:
65
logging.warn("%s: Not going to run strategy as its not enabled.", self.getName())
66
return
67
68
if Utils.isMarketClosedForTheDay():
69
logging.warn("%s: Not going to run strategy as market is closed.", self.getName())
70
return
71
72
now = datetime.now()
73
if now < Utils.getMarketStartTime():
74
Utils.waitTillMarketOpens(self.getName())
75
76
if self.canTradeToday() == False:
77
logging.warn("%s: Not going to run strategy as it cannot be traded today.", self.getName())
78
return
79
80
now = datetime.now()
81
if now < self.startTimestamp:
82
waitSeconds = Utils.getEpoch(self.startTimestamp) - Utils.getEpoch(now)
83
logging.info("%s: Waiting for %d seconds till startegy start timestamp reaches...", self.getName(), waitSeconds)
84
if waitSeconds > 0:
85
time.sleep(waitSeconds)
86
87
# Run in an loop and keep processing
88
while True:
89
if Utils.isMarketClosedForTheDay():
90
logging.warn("%s: Exiting the strategy as market closed.", self.getName())
91
break
92
93
# Derived class specific implementation will be called when process() is called
94
self.process()
95
96
# Sleep and wake up on every 30th second
97
now = datetime.now()
98
waitSeconds = 30 - (now.second % 30)
99
time.sleep(waitSeconds)
100
101
def shouldPlaceTrade(self, trade, tick):
102
# Each strategy should call this function from its own shouldPlaceTrade() method before working on its own logic
103
if trade == None:
104
return False
105
if trade.qty == 0:
106
TradeManager.disableTrade(trade, 'InvalidQuantity')
107
return False
108
109
now = datetime.now()
110
if now > self.stopTimestamp:
111
TradeManager.disableTrade(trade, 'NoNewTradesCutOffTimeReached')
112
return False
113
114
numOfTradesPlaced = TradeManager.getNumberOfTradesPlacedByStrategy(self.getName())
115
if numOfTradesPlaced >= self.maxTradesPerDay:
116
TradeManager.disableTrade(trade, 'MaxTradesPerDayReached')
117
return False
118
119
return True
120
121
def addTradeToList(self, trade):
122
if trade != None:
123
self.trades.append(trade)
124
125
def getQuote(self, tradingSymbol):
126
return Quotes.getQuote(tradingSymbol, self.isFnO)
127
128
def getTrailingSL(self, trade):
129
return 0
130