-
Notifications
You must be signed in to change notification settings - Fork 1
/
BollingerBandStrategy.py
144 lines (120 loc) · 4.92 KB
/
BollingerBandStrategy.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
Title: Bollinger Band Strategy (NSE)
Description: This is a long short strategy based on bollinger bands
and SMA dual signals
Style tags: Systematic Fundamental
Asset class: Equities, Futures, ETFs and Currencies
Dataset: NSE
"""
from blueshift.library.technicals.indicators import bollinger_band, ema
from blueshift.finance import commission, slippage
from blueshift.api import( symbol,
order_target_percent,
set_commission,
set_slippage,
schedule_function,
date_rules,
time_rules,
)
def initialize(context):
"""
A function to define things to do at the start of the strategy
"""
# universe selection
context.securities = [symbol('ADANIENT')]
# context.securities = [symbol('TATAELXSI'), symbol('ADANIENT')]
# context.securities = [symbol('NIFTY-I'),symbol('BANKNIFTY-I')]
# context.stock = symbol("HAL")
# context.stock = symbol("TATAELXSI")
# context.stock = symbol("ADANIENT")
# define strategy parameters
context.params = {'indicator_lookback':375,
'indicator_freq':'1m',
'buy_signal_threshold':0.5,
'sell_signal_threshold':-0.5,
'SMA_period_short':15,
'SMA_period_long':60,
'BBands_period':300,
'trade_freq':60, # 5
'leverage':1} # 2
# indicator_lookback & indicator_freq : past data params to use to generate signals
# trade_freq: run_strategy will be scheduled every trade_freq mins
# leverage: scaling factor to decide bet size
# variables to track signals and target portfolio
context.signals = dict((security,0) for security in context.securities) # -1/0/1
context.target_position = dict((security,0) for security in context.securities)
# set trading cost and slippage to zero
set_commission(commission.PerShare(cost=0.0, min_trade_cost=0.0))
set_slippage(slippage.FixedSlippage(0.00))
freq = int(context.params['trade_freq'])
schedule_function(run_strategy, date_rules.every_day(),
time_rules.every_nth_minute(freq))
schedule_function(stop_trading, date_rules.every_day(),
time_rules.market_close(minutes=30))
context.trade = True
def before_trading_start(context, data):
context.trade = True
def stop_trading(context, data):
context.trade = False
def run_strategy(context, data):
"""
A function to define core strategy steps
"""
if not context.trade:
return
generate_signals(context, data)
generate_target_position(context, data)
rebalance(context, data)
def rebalance(context,data):
"""
A function to rebalance - all execution logic goes here
"""
for security in context.securities:
order_target_percent(security, context.target_position[security])
def generate_target_position(context, data):
"""
A function to define target portfolio
"""
num_secs = len(context.securities)
weight = round(1.0/num_secs,2)*context.params['leverage']
for security in context.securities:
if context.signals[security] > context.params['buy_signal_threshold']:
context.target_position[security] = weight
elif context.signals[security] < context.params['sell_signal_threshold']:
context.target_position[security] = -weight
else:
context.target_position[security] = 0
def generate_signals(context, data):
"""
A function to define define the signal generation
"""
try:
price_data = data.history(context.securities, 'close',
context.params['indicator_lookback'],
context.params['indicator_freq'])
except:
return
for security in context.securities:
px = price_data.loc[:,security].values
context.signals[security] = signal_function(px, context.params)
def signal_function(px, params):
"""
The main trading logic goes here, called by generate_signals above
"""
upper, mid, lower = bollinger_band(px,params['BBands_period'])
if upper - lower == 0:
return 0
ind2 = ema(px, params['SMA_period_short'])
ind3 = ema(px, params['SMA_period_long'])
last_px = px[-1]
dist_to_upper = 100*(upper - last_px)/(upper - lower)
if dist_to_upper > 95:
return -1
elif dist_to_upper < 5:
return 1
elif dist_to_upper > 40 and dist_to_upper < 60 and ind2-ind3 < 0:
return -1
elif dist_to_upper > 40 and dist_to_upper < 60 and ind2-ind3 > 0:
return 1
else:
return 0