-
Notifications
You must be signed in to change notification settings - Fork 2
/
(IK) Base Break Buy.pine
224 lines (222 loc) · 11.8 KB
/
(IK) Base Break Buy.pine
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
Script Name: (IK) Base Break Buy
Author: tapRoot_coding
Description: This strategy first calculates areas of support (bases), and then enters trades if that support is broken. The idea is to profit off of retracement. Dollar-cost-averaging safety orders are key here. This strategy takes into account a .1% commission, and tests are done with an initial capital of 100.00 USD. This only goes long.
The strategy is highly customizable....
PineScript code:
Pine Script™ strategy
(IK) Base Break Buy
Copy code
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
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © userIan
//@version=4
strategy("(IK) Base Break Buy", overlay=true, pyramiding=6, precision=2, default_qty_type=strategy.cash, initial_capital=100.0, currency="USD", commission_type=strategy.commission.percent, commission_value=0.1)
// == INPUT ==
i_baseMax = input(group="Base Calculations", title="Max Bases", type=input.integer, defval=3, minval=1, maxval=10) // max amount of bases on the chart at any specific time
i_dev = input(group="Base Calculations", title="Base Area Deviation", type=input.float, defval=0.005, minval=0.0, maxval=1.0) // if enough recent bars had bottoms within this deviation of the current bar's bottom, a base is created
i_baseDev = input(group="Base Calculations", title="Unique Base Deviation", type=input.float, defval=0.05, minval=0.0, maxval=1.0) // bases cannot be created if they fall within this deviation of an extant base
i_baseSource = input(group="Base Calculations", title="Base Source", options=["Close or Open", "Low"], defval="Close or Open") // should base calcuations be based off of candlestick closes and opens (whichever is lower), or candlestick lows
i_lookback = input(group="Base Calculations", title="Lookback", type=input.integer, defval=100) // how many bars back do we check to confirm current bases
i_confLevel = input(group="Base Calculations", title="Confidence Level", type=input.float, defval=0.01, minval=0.0, maxval=1.0) // what percentage of historical bars bottoming within deviation are needed to confirm a base
i_breakThresh = input(group="Base Break Detection", title="Break Threshold", type=input.float, defval=0.02, minval=0.0, maxval=1.0) // how far (by percentage) does price have to fall below a base to constitute a 'break'
i_breakWindow = input(group="Base Break Detection", title="Break Window", type=input.integer, defval=5) // how many bars should we allow for price to fall below the break threshold before it's no longer a tradable break
i_initialOrder = input(group="Order Settings", title="Initial Order Capital", type=input.float, defval=0.2, minval=0.0, maxval=1.0) // what percentage of capital to use in initial trade entry
i_safetyCount = input(group="Order Settings", title="Safety Order Max Count", type=input.integer, defval=3, minval=0, maxval=5) // maximum amount of safety orders per trade. remaining capital after initial entry will be divided evenly among these
i_safetyThresh = input(group="Order Settings", title="Safter Order Threshold", type=input.float, defval=0.03, minval=0.0, maxval=1.0) // what percentage does price need to fall to activate a safety order
i_stopLoss = input(group="Order Settings", title="Stop Loss", type=input.float, defval=0.2, minval=0.0, maxval=1.0) // what percentage does price need to fall to activate a stop loss
i_stopLossType = input(group="Order Settings", title="Stop Loss Type", options=['From Initial Entry', 'From Price Average'], defval='From Price Average') // calculate static stop loss based on price at first entry, or dynamic stop loass based on position average price
// == FUNCTIONS ==
// is _val1 within the deviation (_dev) of _val2?
f_isCloseTo(_val1, _val2, _dev) => (_val1 <= _val2*(1+_dev)) and (_val1 >= _val2*(1-_dev))
// is this confirmed base (_val) distant enough (outside of deviation _dev) from another confirmed base (in _arr)?
f_newBase(_val, _arr, _dev) =>
result = true
if array.size(_arr) > 0
for i = 0 to array.size(_arr)-1
if (_val <= array.get(_arr, i)*(1+_dev)) and (_val >= array.get(_arr, i)*(1-_dev))
result := false
result
// == VARIABLES ==
var bases = array.new_float() // reference to every current base
var closestBase = float(na) // the closest base to currenct price (only below price)
var brokenBase = float(na) // the base that has been recently broken
var baseBreakIndex = int(na) // when the most recent base was broken
var takeProfit = float(na) // dynamic take profit percentage base on severity of base break
var safetyOrderQty = ((strategy.initial_capital*(1-i_initialOrder))/i_safetyCount)/100 // percentage of capital to use for each safety order
var safetyCount = 0 // keep track of how many safety orders we've made
// == LOGIC ==
// detect bases and add unique bases to base array
currentBot = i_baseSource == "Low" ? low : min(close,open)
count = 0
for i = 1 to i_lookback
bot = i_baseSource == "Low" ? low[i] : min(close[i],open[i])
if f_isCloseTo(currentBot, bot, i_dev)
count := count +1
if count >= (i_lookback * i_confLevel) and f_newBase(currentBot, bases, i_baseDev)
array.unshift(bases, currentBot)
// prune base array
if array.size(bases) > i_baseMax
array.pop(bases)
// detect base break
if crossunder(close, closestBase) and strategy.position_size == 0
baseBreakIndex := bar_index
brokenBase := closestBase
// reset baseBreak if window has expired; this is no longer a tradable break
if (bar_index - baseBreakIndex > i_breakWindow) and strategy.position_size == 0
brokenBase := na
// update closest base
if array.size(bases) > 0
array.sort(bases, order.descending)
for i = 0 to array.size(bases)-1
if array.get(bases, i) < close
closestBase := array.get(bases,i)
break
// reset safety count if a trade has just been exited
if strategy.position_size == 0
safetyCount := 0
// == ENTRY AND EXIT ==
// enter trade if break is confirmed and set the takeProfit percentage
if close < (brokenBase * (1-i_breakThresh)) and strategy.position_size == 0 and barstate.isconfirmed
strategy.entry(id="Long", long=strategy.long, qty=(strategy.initial_capital * i_initialOrder)/close, comment='buy')
takeProfit := 1-(close/brokenBase)
// safety order
if close < (strategy.position_avg_price * (1-i_safetyThresh)) and safetyCount < i_safetyCount
safetyCount := safetyCount + 1
strategy.entry(id="Long", long=strategy.long, qty=(strategy.initial_capital * safetyOrderQty)/close, comment='safety')
// exit trade
strategy.exit(id="Long", stop=i_stopLossType == "From Price Average" ? strategy.position_avg_price * (1-i_stopLoss) : brokenBase * (1-i_stopLoss), comment='sell-stop')
if (close > strategy.position_avg_price * (1+takeProfit)) and barstate.isconfirmed
strategy.close("Long", comment='sell-profit')
brokenBase := na
// == PLOT ==
plotTimer = bar_index % 2 == 0 // this creates a dashed line
plot(array.size(bases) > 0 and plotTimer ? array.get(bases,0) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 1 and plotTimer ? array.get(bases,1) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 2 and plotTimer ? array.get(bases,2) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 3 and plotTimer ? array.get(bases,3) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 4 and plotTimer ? array.get(bases,4) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 5 and plotTimer ? array.get(bases,5) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 6 and plotTimer ? array.get(bases,6) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 7 and plotTimer ? array.get(bases,7) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 8 and plotTimer ? array.get(bases,8) : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 9 and plotTimer ? array.get(bases,9) : na, color=color.white, style=plot.style_linebr)
plot(closestBase == closestBase[1] and strategy.position_size == 0 ? closestBase : na, color=color.yellow, style=plot.style_linebr) // yellow line for closest base (if not in trade)
plot(brokenBase, color=color.purple, style=plot.style_linebr) // purple line for the broken base that triggered the trade
plot(strategy.position_avg_price * (1+takeProfit), color=color.silver, style=plot.style_linebr) // silver line for target profit
plot(i_stopLossType == "From Price Average" ? strategy.position_avg_price * (1-i_stopLoss) : brokenBase * (1-i_stopLoss), color=color.red, style=plot.style_linebr) // red line for stop loss
Expand (112 lines)