Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sreenivasdoosa
GitHub Repository: sreenivasdoosa/sdoosa-algo-trade-python
Path: blob/master/src/strategies/OptionSelling.py
301 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 OptionSelling(BaseStrategy):
14
__instance = None
15
16
@staticmethod
17
def getInstance(): # singleton class
18
if OptionSelling.__instance == None:
19
OptionSelling()
20
return OptionSelling.__instance
21
22
def __init__(self):
23
if OptionSelling.__instance != None:
24
raise Exception("This class is a singleton!")
25
else:
26
OptionSelling.__instance = self
27
# Call Base class constructor
28
super().__init__("OptionSelling")
29
# Initialize all the properties specific to this strategy
30
self.productType = ProductType.MIS
31
self.symbols = []
32
self.slPercentage = 50
33
self.targetPercentage = 0
34
self.startTimestamp = Utils.getTimeOfToDay(9, 30, 0) # When to start the strategy. Default is Market start time
35
self.stopTimestamp = Utils.getTimeOfToDay(14, 30, 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(15, 15, 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
if Utils.isTodayOneDayBeforeWeeklyExpiryDay() == True:
45
logging.info('%s: Today is one day before weekly expiry date hence going to trade this strategy', self.getName())
46
return True
47
if Utils.isTodayWeeklyExpiryDay() == True:
48
logging.info('%s: Today is weekly expiry day hence going to trade this strategy today', self.getName())
49
return True
50
logging.info('%s: Today is neither day before expiry nor expiry day. Hence NOT going to trade this strategy today', self.getName())
51
return False
52
53
def process(self):
54
now = datetime.now()
55
if now < self.startTimestamp:
56
return
57
if len(self.trades) >= self.maxTradesPerDay:
58
return
59
60
# Get current market price of Nifty Future
61
futureSymbol = Utils.prepareMonthlyExpiryFuturesSymbol('NIFTY')
62
quote = self.getQuote(futureSymbol)
63
if quote == None:
64
logging.error('%s: Could not get quote for %s', self.getName(), futureSymbol)
65
return
66
67
ATMStrike = Utils.getNearestStrikePrice(quote.lastTradedPrice, 50)
68
logging.info('%s: Nifty CMP = %f, ATMStrike = %d', self.getName(), quote.lastTradedPrice, ATMStrike)
69
70
ATMPlus50CESymbol = Utils.prepareWeeklyOptionsSymbol("NIFTY", ATMStrike + 50, 'CE')
71
ATMMinus50PESymbol = Utils.prepareWeeklyOptionsSymbol("NIFTY", ATMStrike - 50, 'PE')
72
logging.info('%s: ATMPlus50CE = %s, ATMMinus50PE = %s', self.getName(), ATMPlus50CESymbol, ATMMinus50PESymbol)
73
# create trades
74
self.generateTrades(ATMPlus50CESymbol, ATMMinus50PESymbol)
75
76
def generateTrades(self, ATMPlus50CESymbol, ATMMinus50PESymbol):
77
numLots = self.calculateLotsPerTrade()
78
quoteATMPlus50CESymbol = self.getQuote(ATMPlus50CESymbol)
79
quoteATMMinus50PESymbol = self.getQuote(ATMMinus50PESymbol)
80
if quoteATMPlus50CESymbol == None or quoteATMMinus50PESymbol == None:
81
logging.error('%s: Could not get quotes for option symbols', self.getName())
82
return
83
84
self.generateTrade(ATMPlus50CESymbol, numLots, quoteATMPlus50CESymbol.lastTradedPrice)
85
self.generateTrade(ATMMinus50PESymbol, numLots, quoteATMMinus50PESymbol.lastTradedPrice)
86
logging.info('%s: Trades generated.', self.getName())
87
88
def generateTrade(self, optionSymbol, numLots, lastTradedPrice):
89
trade = Trade(optionSymbol)
90
trade.strategy = self.getName()
91
trade.isOptions = True
92
trade.direction = Direction.SHORT # Always short here as option selling only
93
trade.productType = self.productType
94
trade.placeMarketOrder = True
95
trade.requestedEntry = lastTradedPrice
96
trade.timestamp = Utils.getEpoch(self.startTimestamp) # setting this to strategy timestamp
97
98
isd = Instruments.getInstrumentDataBySymbol(optionSymbol) # Get instrument data to know qty per lot
99
trade.qty = isd['lot_size'] * numLots
100
101
trade.stopLoss = Utils.roundToNSEPrice(trade.requestedEntry + trade.requestedEntry * self.slPercentage / 100)
102
trade.target = 0 # setting to 0 as no target is applicable for this trade
103
104
trade.intradaySquareOffTimestamp = Utils.getEpoch(self.squareOffTimestamp)
105
# Hand over the trade to TradeManager
106
TradeManager.addNewTrade(trade)
107
108
def shouldPlaceTrade(self, trade, tick):
109
# First call base class implementation and if it returns True then only proceed
110
if super().shouldPlaceTrade(trade, tick) == False:
111
return False
112
# We dont have any condition to be checked here for this strategy just return True
113
return True
114
115