Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sreenivasdoosa
GitHub Repository: sreenivasdoosa/sdoosa-algo-trade-python
Path: blob/master/src/strategies/ShortStraddleBNF.py
300 views
1
import logging
2
from datetime import datetime
3
4
from instruments.Instruments import Instruments
5
from models.Direction import Direction
6
from models.ProductType import ProductType
7
from strategies.BaseStrategy import BaseStrategy
8
from utils.Utils import Utils
9
from trademgmt.Trade import Trade
10
from trademgmt.TradeManager import TradeManager
11
12
# Each strategy has to be derived from BaseStrategy
13
class ShortStraddleBNF(BaseStrategy):
14
__instance = None
15
16
@staticmethod
17
def getInstance(): # singleton class
18
if ShortStraddleBNF.__instance == None:
19
ShortStraddleBNF()
20
return ShortStraddleBNF.__instance
21
22
def __init__(self):
23
if ShortStraddleBNF.__instance != None:
24
raise Exception("This class is a singleton!")
25
else:
26
ShortStraddleBNF.__instance = self
27
# Call Base class constructor
28
super().__init__("ShortStraddleBNF")
29
# Initialize all the properties specific to this strategy
30
self.productType = ProductType.MIS
31
self.symbols = []
32
self.slPercentage = 30
33
self.targetPercentage = 0
34
self.startTimestamp = Utils.getTimeOfToDay(11, 0, 0) # When to start the strategy. Default is Market start time
35
self.stopTimestamp = Utils.getTimeOfToDay(14, 0, 0) # 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.
36
self.squareOffTimestamp = Utils.getTimeOfToDay(14, 30, 0) # Square off time
37
self.capital = 100000 # Capital to trade (This is the margin you allocate from your broker account for this strategy)
38
self.leverage = 0
39
self.maxTradesPerDay = 2 # (1 CE + 1 PE) Max number of trades per day under this strategy
40
self.isFnO = True # Does this strategy trade in FnO or not
41
self.capitalPerSet = 100000 # Applicable if isFnO is True (1 set means 1CE/1PE or 2CE/2PE etc based on your strategy logic)
42
43
def canTradeToday(self):
44
# Even if you remove this function canTradeToday() completely its same as allowing trade every day
45
return True
46
47
def process(self):
48
now = datetime.now()
49
if now < self.startTimestamp:
50
return
51
if len(self.trades) >= self.maxTradesPerDay:
52
return
53
54
# Get current market price of Nifty Future
55
futureSymbol = Utils.prepareMonthlyExpiryFuturesSymbol('BANKNIFTY')
56
quote = self.getQuote(futureSymbol)
57
if quote == None:
58
logging.error('%s: Could not get quote for %s', self.getName(), futureSymbol)
59
return
60
61
ATMStrike = Utils.getNearestStrikePrice(quote.lastTradedPrice, 100)
62
logging.info('%s: Nifty CMP = %f, ATMStrike = %d', self.getName(), quote.lastTradedPrice, ATMStrike)
63
64
ATMCESymbol = Utils.prepareWeeklyOptionsSymbol("BANKNIFTY", ATMStrike, 'CE')
65
ATMPESymbol = Utils.prepareWeeklyOptionsSymbol("BANKNIFTY", ATMStrike, 'PE')
66
logging.info('%s: ATMCESymbol = %s, ATMPESymbol = %s', self.getName(), ATMCESymbol, ATMPESymbol)
67
# create trades
68
self.generateTrades(ATMCESymbol, ATMPESymbol)
69
70
def generateTrades(self, ATMCESymbol, ATMPESymbol):
71
numLots = self.calculateLotsPerTrade()
72
quoteATMCESymbol = self.getQuote(ATMCESymbol)
73
quoteATMPESymbol = self.getQuote(ATMPESymbol)
74
if quoteATMCESymbol == None or quoteATMPESymbol == None:
75
logging.error('%s: Could not get quotes for option symbols', self.getName())
76
return
77
78
self.generateTrade(ATMCESymbol, numLots, quoteATMCESymbol.lastTradedPrice)
79
self.generateTrade(ATMPESymbol, numLots, quoteATMPESymbol.lastTradedPrice)
80
logging.info('%s: Trades generated.', self.getName())
81
82
def generateTrade(self, optionSymbol, numLots, lastTradedPrice):
83
trade = Trade(optionSymbol)
84
trade.strategy = self.getName()
85
trade.isOptions = True
86
trade.direction = Direction.SHORT # Always short here as option selling only
87
trade.productType = self.productType
88
trade.placeMarketOrder = True
89
trade.requestedEntry = lastTradedPrice
90
trade.timestamp = Utils.getEpoch(self.startTimestamp) # setting this to strategy timestamp
91
92
isd = Instruments.getInstrumentDataBySymbol(optionSymbol) # Get instrument data to know qty per lot
93
trade.qty = isd['lot_size'] * numLots
94
95
trade.stopLoss = Utils.roundToNSEPrice(trade.requestedEntry + trade.requestedEntry * self.slPercentage / 100)
96
trade.target = 0 # setting to 0 as no target is applicable for this trade
97
98
trade.intradaySquareOffTimestamp = Utils.getEpoch(self.squareOffTimestamp)
99
# Hand over the trade to TradeManager
100
TradeManager.addNewTrade(trade)
101
102
def shouldPlaceTrade(self, trade, tick):
103
# First call base class implementation and if it returns True then only proceed
104
if super().shouldPlaceTrade(trade, tick) == False:
105
return False
106
# We dont have any condition to be checked here for this strategy just return True
107
return True
108
109
def getTrailingSL(self, trade):
110
if trade == None:
111
return 0
112
if trade.entry == 0:
113
return 0
114
lastTradedPrice = TradeManager.getLastTradedPrice(trade.tradingSymbol)
115
if lastTradedPrice == 0:
116
return 0
117
118
trailSL = 0
119
profitPoints = int(trade.entry - lastTradedPrice)
120
if profitPoints >= 5:
121
factor = int(profitPoints / 5)
122
trailSL = Utils.roundToNSEPrice(trade.initialStopLoss - factor * 5)
123
logging.info('%s: %s Returning trail SL %f', self.getName(), trade.tradingSymbol, trailSL)
124
return trailSL
125
126
127