-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathSPXic.py
113 lines (104 loc) · 5.54 KB
/
SPXic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#region imports
from AlgorithmImports import *
#endregion
from .Base import Base
class SPXic(Base):
PARAMETERS = {
# The start time at which the algorithm will start scheduling the strategy execution (to open new positions). No positions will be opened before this time
"scheduleStartTime": time(9, 30, 0),
# The stop time at which the algorithm will look to open a new position.
"scheduleStopTime": time(16, 0, 0),
# Periodic interval with which the algorithm will check to open new positions
"scheduleFrequency": timedelta(minutes = 5),
# Maximum number of open positions at any given time
"maxActivePositions": 10,
# Maximum number of open orders (not filled) at any given time
"maxOpenPositions":1,
# Control whether to allow multiple positions to be opened for the same Expiration date
"allowMultipleEntriesPerExpiry": True,
# Minimum time distance between opening two consecutive trades
"minimumTradeScheduleDistance": timedelta(minutes=10),
# Days to Expiration
"dte": 0,
# The size of the window used to filter the option chain: options expiring in the range [dte-dteWindow, dte] will be selected
"dteWindow": 0,
"useLimitOrders": True,
"limitOrderRelativePriceAdjustment": 0.2,
# Alternative method to set the absolute price (per contract) of the Limit Order. This method is used if a number is specified
"limitOrderAbsolutePrice": 1.0,
"limitOrderExpiration": timedelta(minutes=5),
# Coarse filter for the Universe selection. It selects nStrikes on both sides of the ATM
# strike for each available expiration
# Example: 200 SPX @ 3820 & 3910C w delta @ 1.95 => 90/5 = 18
"nStrikesLeft": 18,
"nStrikesRight": 18,
# TODO fix this and set it based on buying power.
# "maxOrderQuantity": 200,
# COMMENT OUT this one below because it caused the orderQuantity to be 162 and maxOrderQuantity to be 10 so it would not place trades.
"targetPremiumPct": 0.01,
"validateQuantity": False,
# Minimum premium accepted for opening a new position. Setting this to None disables it.
"minPremium": 0.9,
# Maximum premium accepted for opening a new position. Setting this to None disables it.
"maxPremium": 1.2,
# Profit Target Factor (Multiplier of the premium received/paid when the position was opened)
"profitTarget": 1.0,
"bidAskSpreadRatio": 0.4,
"validateBidAskSpread": True,
"marketCloseCutoffTime": time(15, 45, 0),
# Put/Call Wing size for Iron Condor, Iron Fly
"putWingSize": 10,
"callWingSize": 10,
# "targetPremium": 500,
}
def __init__(self, context):
# Call the Base class __init__ method
super().__init__(context)
# You can change the name here
self.name = "SPXic"
self.nameTag = "SPXic"
self.ticker = "SPX"
self.context.structure.AddUnderlying(self, self.ticker)
self.logger.debug(f"{self.__class__.__name__} -> __init__ -> AddUnderlying")
def getOrder(self, chain, data):
self.logger.debug(f"{self.__class__.__name__} -> getOrder -> start")
self.logger.debug(f"SPXic -> getOrder -> data.ContainsKey(self.underlyingSymbol): {data.ContainsKey(self.underlyingSymbol)}")
self.logger.debug(f"SPXic -> getOrder -> Underlying Symbol: {self.underlyingSymbol}")
# Best time to open the trade: 9:45 + 10:15 + 12:30 + 13:00 + 13:30 + 13:45 + 14:00 + 15:00 + 15:15 + 15:45
# https://tradeautomationtoolbox.com/byob-ticks/?save=admZ4dG
if data.ContainsKey(self.underlyingSymbol):
self.logger.debug(f"SPXic -> getOrder: Data contains key {self.underlyingSymbol}")
# trade_times = [time(9, 45, 0), time(10, 15, 0), time(12, 30, 0), time(13, 0, 0), time(13, 30, 0), time(13, 45, 0), time(14, 0, 0), time(15, 0, 0), time(15, 15, 0), time(15, 45, 0)]
trade_times = [time(9, 45, 0), time(10, 15, 0), time(12, 30, 0), time(13, 0, 0), time(13, 30, 0), time(13, 45, 0), time(14, 0, 0)]
# trade_times = [time(hour, minute, 0) for hour in range(9, 15) for minute in range(0, 60, 30) if not (hour == 15 and minute > 0)]
# Remove the microsecond from the current time
current_time = self.context.Time.time().replace(microsecond=0)
self.logger.debug(f"SPXic -> getOrder -> current_time: {current_time}")
self.logger.debug(f"SPXic -> getOrder -> trade_times: {trade_times}")
self.logger.debug(f"SPXic -> getOrder -> current_time in trade_times: {current_time in trade_times}")
if current_time not in trade_times:
return None
call = self.order.getSpreadOrder(
chain,
'call',
fromPrice=self.minPremium,
toPrice=self.maxPremium,
wingSize=self.callWingSize,
sell=True
)
put = self.order.getSpreadOrder(
chain,
'put',
fromPrice=self.minPremium,
toPrice=self.maxPremium,
wingSize=self.putWingSize,
sell=True
)
self.logger.debug(f"SPXic -> getOrder: Call: {call}")
self.logger.debug(f"SPXic -> getOrder: Put: {put}")
if call is not None and put is not None:
return [call, put]
else:
return None
else:
return None