View difference between Paste ID: zJNUMNnJ and jE12AWvP
SHOW: | | - or go back to the newest paste.
1
#######################
2
### TRENDATRON 5000 ###
3
#######################
4
5
### INTRO
6
https://cryptotrader.org/strategies/peKY35zY2Z2G56rLi
7
by aspiramedia (https://cryptotrader.org/aspiramedia)
8
9
Please PM me with any updates, feedback, bugs, suggestions, criticism etc.
10
Please leave this header intact, adding your own comments in EDITOR'S COMMENTS.
11
Edited bots are NOT for submission into the CryptoTrader.org Strategies section.
12
###
13
14
### EDITOR'S COMMENTS
15
Made any edits? Why not explain here.
16
###
17
18
### DONATIONS
19
I am releasing this as a donation based bot. I am releasing this in hope of obtaining some donations from users here.
20
Please donate BTC to: 1GGZU5mAUSLxVDegdxjakTLqZy7zizRH74
21
###
22
23
### DISCLAIMER
24
As usual with all trading, only trade with what you are able to lose.
25
Start small.
26
I am NOT responsible for your losses if any occur.
27
###
28
29
### CREDITS
30
The VIX and Swing indicators used here were originally by Chris Moody at TradingView.
31
Trading logic is my own.
32
Thanks to all at Cryptotrader.org that helped me along the way.
33
###
34
35
### ADVICE
36
Rather than just trading with this, I strongly recommend making this bot your own.
37
Use it as a learning tool.
38
Edit it to trade as you like to match your strategy.
39
View this as a template for a long term trend trader with added scalping.
40
Backtesting is your friend. Backtest over long periods to identify strengths and weaknesses.
41
###
42
43
44
############
45
### CODE ###
46
############
47
48
STOP_LOSS = askParam 'Use a Stop Loss?', false
49
STOP_LOSS_PERCENTAGE = askParam 'If so, Stop Loss Percentage?', 5
50
SCALP = askParam 'Use Scalping?', true
51
SPLIT = askParam 'Split orders up?', false
52
SPLIT_AMOUNT = askParam 'If so, split into how many?', 4
53
PERIOD = askParam 'Trend reaction time (Max = 250 | Min = 50 | Default = 250 )', 250
54
55
class VIX
56
    constructor: (@period) ->
57
        @close = []
58
        @wvf = []
59
        @trade = []
60
        @count = 0
61
62
        # INITIALIZE ARRAYS
63
        for [@close.length..22]
64
            @close.push 0
65
        for [@wvf.length..@period]
66
            @wvf.push 0
67
        for [@trade.length..10]
68
            @trade.push 0
69
        
70
    calculate: (instrument) ->
71
72
        close = instrument.close[instrument.close.length-1]
73
        high = instrument.high[instrument.high.length-1]
74
        low = instrument.low[instrument.low.length-1]
75
        
76
77
        # INCREASE DATA COUNT
78
        @count++
79
        
80
        # REMOVE OLD DATA
81
        @close.pop()
82
        @wvf.pop()
83
        @trade.pop()
84
85
        # ADD NEW DATA
86
        @close.unshift(0)
87
        @wvf.unshift(0)
88
        @trade.unshift(0)
89
90
        # CALCULATE 
91
        @close[0] = close
92
        
93
        highest = (@close.reduce (a,b) -> Math.max a, b)
94
95
        @wvf[0] = ((highest - low) / (highest)) * 100
96
97
        sdev = talib.STDDEV
98
            inReal: @wvf
99
            startIdx: 0
100
            endIdx: @wvf.length-1
101
            optInTimePeriod: @period
102
            optInNbDev: 1
103
        sdev = sdev[sdev.length-1]
104
105
        midline = talib.SMA
106
            inReal: @wvf
107
            startIdx: 0
108
            endIdx: @wvf.length-1
109
            optInTimePeriod: @period
110
        midline = midline[midline.length-1]
111
112
        lowerband = midline - sdev
113
        upperband = midline + sdev
114
115
        rangehigh = (@wvf.reduce (a,b) -> Math.max a, b) * 0.85
116
        rangelow = (@wvf.reduce (a,b) -> Math.min a, b) * 1.01
117
118
        if @wvf[0] >= upperband or @wvf[0] >= rangehigh
119
            @trade[0] = 0
120
            plotMark
121
                "wvf1": @wvf[0]
122
        else
123
            @trade[0] = 1
124
            plotMark
125
                "wvf2": @wvf[0]
126
            
127
128
        # RETURN DATA
129
        result =
130
            wvf: @wvf[0]
131
            rangehigh: rangehigh
132
            rangelow: rangelow
133
            trade: @trade
134
135
        return result 
136
137
class GANNSWING
138
    constructor: (@period) ->
139
        @count = 0
140
        @buycount = 0
141
        @sellcount = 0
142
        @lowma = []
143
        @highma = []
144
145
        # INITIALIZE ARRAYS
146
        for [@lowma.length..5]
147
            @lowma.push 0
148
        for [@highma.length..5]
149
            @highma.push 0
150
        
151
    calculate: (instrument) ->        
152
153
        close = instrument.close[instrument.close.length-1]
154
        high = instrument.high[instrument.high.length-1]
155
        low = instrument.low[instrument.low.length-1]
156
157
        # REMOVE OLD DATA
158
        @lowma.pop()
159
        @highma.pop()
160
161
        # ADD NEW DATA
162
        @lowma.unshift(0)
163
        @highma.unshift(0)
164
165
        # CALCULATE
166
        highma = talib.SMA
167
            inReal: instrument.high
168
            startIdx: 0
169
            endIdx: instrument.high.length-1
170
            optInTimePeriod: @period
171
        @highma[0] = highma[highma.length-1]
172
173
        lowma = talib.SMA
174
            inReal: instrument.low
175
            startIdx: 0
176
            endIdx: instrument.low.length-1
177
            optInTimePeriod: @period
178
        @lowma[0] = lowma[lowma.length-1]
179
180
        if close > @highma[1]
181
            hld = 1
182
        else if close < @lowma[1]
183
            hld = -1
184
        else
185
            hld = 0
186
187
        if hld != 0
188
            @count++
189
190
        if hld != 0 && @count == 1
191
            hlv = hld
192
            @count = 0
193
        else
194
            hlv = 0
195
196
        if hlv == -1
197
            hi = @highma[0]
198
            plotMark
199
                "hi": hi * 1.01
200
            @sellcount++
201
            @buycount = 0
202
203
        if hlv == 1
204
            lo = @lowma[0]
205
            plotMark
206
                "lo": lo / 1.01
207
            @buycount++
208
            @sellcount = 0
209
210
        if @buycount == 3
211
            tradebuy = true
212
            @buycount = 0
213
        else
214
            tradebuy = false
215
216
217
        if @sellcount == 3
218
            tradesell = true
219
            @sellcount = 0
220
        else
221
            tradesell = false
222
    
223
224
        # RETURN DATA
225
        result =
226
            tradesell: tradesell
227
            tradebuy: tradebuy
228
229
        return result 
230
231
class FUNCTIONS
232
    
233
    @ROUND_DOWN: (value, places) ->
234
        offset = Math.pow(10, places)
235
        return Math.floor(value*offset)/offset
236
        
237
class TRADE    
238
    
239
    @BUY: (instrument, amount, split, timeout) ->
240
        price = instrument.price * 1.01
241
242
        if split > 0
243
            amount = FUNCTIONS.ROUND_DOWN((portfolio.positions[instrument.curr()].amount/split)/price, 8)
244
            for [0..split]
245
                buy(instrument, amount, price, timeout)
246
        else
247
            buy(instrument, null, price, timeout)
248
        
249
    @SELL: (instrument, amount, split, timeout) ->
250
        price = instrument.price * 0.99
251
252
        if split > 0
253
            amount = FUNCTIONS.ROUND_DOWN(portfolio.positions[instrument.asset()].amount/split, 8)
254
            for [0..split]
255
                sell(instrument, amount, price, timeout)
256
        else
257
            sell(instrument, amount, price, timeout)      
258
259
init: (context)->
260
    
261
    context.vix = new VIX(20)               # Period of stddev and midline
262
    context.swing = new GANNSWING(PERIOD)   # Period of highma and lowma
263
264
    # FOR FINALISE STATS
265
    context.balance_curr = 0
266
    context.balance_btc = 0
267
    context.price = 0
268
269
    # TRADING
270
    if SPLIT
271
        context.trade_split = SPLIT_AMOUNT
272
    else
273
        context.trade_split = 0
274
    context.trade_timeout   = 3000
275
276
    # LOGGING
277
    context.TICK = 0
278
    context.balance_curr_start = 0
279
    context.balance_btc_start = 0
280
    context.price_start = 0
281
282
    # WELCOME
283
    info "###"
284
    info "Welcome to the Trendatron Bot."
285
    info "Thanks for choosing this free bot. As many hours have gone into its creation, please consider a donation to:"
286
    info "BTC: 1GGZU5mAUSLxVDegdxjakTLqZy7zizRH74"
287
    info "(The bot carries on regardless of donations - don't worry. And if you have donated then thank you.)"
288
    if STOP_LOSS == true
289
        info "You chose to use a Stop Loss, with a cutoff of " + STOP_LOSS_PERCENTAGE + " percent."
290
    if SCALP == true
291
        info "You chose to use scalping (default bot behaviour)"
292
    if SPLIT == true
293
        info "You chose to split orders up into " + SPLIT_AMOUNT + " orders."
294
295
    info "###"
296
297
298
299
300
handle: (context, data, storage)->
301
302
    instrument = data.instruments[0]
303
    price = instrument.close[instrument.close.length - 1]
304
    storage.lastBuyPrice ?= 0
305
306
    # FOR FINALISE STATS
307
    context.price = instrument.close[instrument.close.length - 1]
308
    context.balance_curr = portfolio.positions[instrument.curr()].amount
309
    context.balance_btc = portfolio.positions[instrument.asset()].amount
310
311
    # CALLING INDICATORS
312
    vix = context.vix.calculate(instrument)
313
    wvf = vix.wvf
314
    rangehigh = vix.rangehigh
315
    rangelow = vix.rangelow
316
    trade = vix.trade
317
318
    swing = context.swing.calculate(instrument)
319
    tradesell = swing.tradesell
320
    tradebuy = swing.tradebuy
321
    
322
323
    # TRADING
324
    if context.balance_curr/price > 0.01
325
        if tradebuy == true
326
            if TRADE.BUY(instrument, null, context.trade_split, context.trade_timeout)
327
                storage.lastBuyPrice = price
328
                storage.stop = true
329
                info "#########"
330
                info "Trend Buy"
331
                info "#########"
332
333
    if context.balance_curr/price > 0.01 && SCALP == true
334
        if trade[0] == 1 && trade[1] == 1 && trade[2] == 0 && trade[3] == 0 && trade[4] == 0 && trade[5] == 0 && wvf > 8.5
335
            if TRADE.BUY(instrument, null, context.trade_split, context.trade_timeout)
336
                storage.lastBuyPrice = price
337
                storage.stop = true
338
                info "#########"
339
                info "Scalp Buy"
340
                info "#########"
341
342
    if context.balance_btc > 0.01
343
        if (tradesell == true && wvf < 2.85) or (tradebuy == true && wvf > 8.5 && trade[0] == 1 && trade[1] == 0)
344
            if TRADE.SELL(instrument, null, context.trade_split, context.trade_timeout)
345
                storage.lastBuyPrice = 0
346
                storage.lastSellPrice = price
347
                storage.stop = false
348
                warn "##########"
349
                warn "Trend Sell"
350
                warn "##########"
351
    
352
    # STOP LOSS
353
    if STOP_LOSS
354
        if storage.stop == true && price < storage.lastBuyPrice * (1 - (STOP_LOSS_PERCENTAGE / 100))
355
            if TRADE.SELL(instrument, null, context.trade_split, context.trade_timeout)
356
                storage.lastBuyPrice = 0
357
                storage.lastSellPrice = price
358
                storage.stop = false
359
                warn "##############"
360
                warn "Stop Loss Sell"
361
                warn "##############"
362
363
    # PLOTTING / DEBUG
364
    plot
365
        wvf: wvf
366
        rangehigh: rangehigh
367
        rangelow: rangelow
368
        normaliser: 25
369
    setPlotOptions
370
        wvf: 
371
            secondary: true
372
        rangehigh: 
373
            secondary: true
374
        rangelow: 
375
            secondary: true
376
        wvf1: 
377
            secondary: true
378
            color: 'blue'
379
        wvf2: 
380
            secondary: true
381
            color: 'black'
382
        lo: 
383
            color: 'green'
384
        hi: 
385
            color: 'red'
386
        normaliser:
387
            secondary: true
388
            color: '#fffdf6'
389
390
    # LOGGING
391
392
    if context.TICK == 0 
393
        context.balance_curr_start = portfolio.positions[instrument.curr()].amount
394
        context.balance_btc_start = portfolio.positions[instrument.asset()].amount
395
        context.price_start = price
396
397
    starting_btc_equiv = context.balance_btc_start + context.balance_curr_start / context.price_start
398
    current_btc_equiv = context.balance_btc + context.balance_curr / price
399
    efficiency = Math.round((current_btc_equiv / starting_btc_equiv) * 1000) / 1000
400
    efficiency_percent = Math.round((((current_btc_equiv / starting_btc_equiv) - 1) * 100) * 100) / 100 
401
402
403
404
    context.TICK++
405
    if Math.round(context.TICK/24) == (context.TICK/24)
406
        warn "### Day " + context.TICK/24 + " Log"
407
        debug "Current Fiat: " + Math.round(context.balance_curr*100)/100 + " | Current BTC: " +  Math.round(context.balance_btc*100)/100
408
        debug "Starting Fiat: " + Math.round(context.balance_curr_start*100)/100 + " | Starting BTC: " +  Math.round(context.balance_btc_start*100)/100
409
        debug "Current Portfolio Worth: " + Math.round(((context.balance_btc * price) + context.balance_curr)*100)/100
410
        debug "Starting Portfolio Worth: " + Math.round(((context.balance_btc_start * context.price_start) + context.balance_curr_start)*100)/100
411
        debug "Efficiency Vs Buy and Hold: " + efficiency + " which equals " + efficiency_percent + "%"
412
        warn "###"
413
414
    if Math.round(context.TICK/744) == (context.TICK/744)
415
        info "###"
416
        info "Thanks for using this free bot for the last month. Please consider a donation to:"
417
        info "BTC: 1GGZU5mAUSLxVDegdxjakTLqZy7zizRH74"
418
        info "(The bot carries on regardless of donations - don't worry. And if you have donated then thank you.)"
419
        info "Or maybe fill in an anonymous survey?"
420
        info "https://docs.google.com/forms/d/1sWjADH4lPvcIy1LJ-N3lz9Bc3dGVefGBCHbzLRFJ7MQ/viewform"
421
        info "###"
422
    
423
424
    
425
finalize: (contex, data)-> 
426
427
    # DISPLAY FINALISE STATS
428
    if context.balance_curr > 10
429
        info "Final BTC Equiv: " + Math.round(context.balance_curr/context.price*100)/100
430
    if context.balance_btc > 0.05
431
        info "Final BTC Value: " + Math.round(context.balance_btc*100)/100