Advertisement
Guest User

Untitled

a guest
May 31st, 2017
643
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Momentum based BTC trader
  2. # Copyright (C) Sam Pollard, 2017 - All Rights Reserved
  3. # Unauthorized copying of this file via any medium is strictly prohibited
  4. # Proprietary and confidential
  5. # Written by Sam Pollard <sam.d.pollard@gmail.com>, May 31, 2017.
  6. # Template code taken from https://cryptotrader.org/backtests/KohMmsLg5Y8NSzJJQ
  7.  
  8. # If you're using this for margin trading, you must trade only with
  9. # Poloniex, specifically BTC/USDT, though Bitfinex may work and trades BTC/USD
  10. # The backtest should start with 100% of your starting account balance in BTC
  11. # This is meant for a period of 1 day.
  12.  
  13. # Version 1, Backtest sent to Kory on May 30, 2017
  14. # https://cryptotrader.org/backtests/WABzEG7wFsXAYd6Yp
  15.  
  16. # margin_trading and trading are mutually exclusive
  17. mt = require 'margin_trading' # May only be done with Binfinex or Poloniex
  18. # trading = require 'trading' # import core trading module
  19. talib = require 'talib' # import technical analysis library
  20.  
  21. # Initialization method called before the script starts.
  22. # Context object holds script data and will be passed to 'handle' method.
  23. init: ->
  24.     # note that init and handle methods don't need arguments
  25.     # @data, @storage and @context can be accessed from anywhere in the code
  26.     @context.OB = 90
  27.     @context.OS = 25
  28.     # This gets complaints at 0.003. For margin trading, it's
  29.     # the amount of ETH (Poloniex) you trade. For trading,
  30.     # it's the minimum %age of your assets you can order.
  31.     @context.eps = 1e-6
  32.     @context.invested = false # You start off all in BTC
  33.     @context.open_short = 0.0
  34.     @context.begin = true
  35.  
  36. # This method is called for each tick
  37. handle: (context, data, storage)->
  38.     # Poloniex: ETH/BTC
  39.     # i.e. the instrument is eth, its price is per bitcoin
  40.     instrument = data.instruments[0]
  41.     price = instrument.price
  42.     RSI = talib.RSI
  43.            inReal: instrument.close
  44.            startIdx: 0
  45.            endIdx: instrument.close.length - 1
  46.            optInTimePeriod: 2
  47.     RSI_value = _.last(RSI)
  48.  
  49.     # TRADING
  50.     # It appears cash and currency are the same thing
  51.     #cash = @portfolio.positions[instrument.base()].amount
  52.     #currency = @portfolio.positions[instrument.curr()].amount
  53.     #assets = @portfolio.positions[instrument.asset()].amount
  54.  
  55.     # MARGIN TRADING
  56.     info = mt.getMarginInfo instrument
  57.     assets = info.margin_balance # The value of all trading assets in BTC (USD for Bitfinex)
  58.     # debug "price = #{price}; assets = #{assets} btc; tradeable balance = #{info.tradable_balance} btc"
  59.     cash = 0
  60.  
  61.     # Stretch and shift
  62.     sf = 0.001
  63.     plot
  64.         RSI: RSI_value  * sf - 100*sf
  65.         OB: @context.OB * sf - 100*sf
  66.         OS: @context.OS * sf - 100*sf
  67.         # TODO: Normalize holdings to the price of 1 ETH
  68.         # Holdings: cash + assets * price
  69.     # Notes:
  70.     # The portfolio object gives access to information about funds
  71.     # instrument.curr() returns base asset id e.g cny
  72.     # instrument.asset() returns traded asset id, for example: "btc"
  73.  
  74.     # MARGIN TRADING
  75.     pos = mt.getPosition instrument
  76.     # check if position is open
  77.     #if pos
  78.     #    debug "position: #{pos.amount} @#{pos.price}"
  79.     #    price = pos.price
  80.     try
  81.         if @context.invested && RSI_value < @context.OS
  82.             if mt.sell instrument, 'limit', 0.99*info.tradable_balance/price, price, instrument.interval * 60
  83.                 pos = mt.getPosition instrument
  84.                 debug "Short sell; new position: #{pos.amount} #{instrument.asset()}"
  85.                 @context.invested = false
  86.                 @context.open_short = Math.abs(pos.amount)
  87.                 # addOrder takes single object as argument
  88.                 # takeProfitOrder = mt.addOrder
  89.                 #     instrument: instrument
  90.                 #     side: 'buy'
  91.                 #     type: 'limit'
  92.                 #     amount: amount
  93.                 #     price: instrument.price * 0.4
  94.                 # @storage.takeProfitOrder = takeProfitOrder.id
  95.         else if RSI_value > @context.OB && info.tradable_balance > @context.eps && !@context.invested
  96.             if mt.buy instrument, 'limit', 0.99*@context.open_short, price, instrument.interval * 60
  97.                 pos = mt.getPosition instrument
  98.                 if pos
  99.                     debug "Buy; new position: #{pos.amount} #{instrument.asset()}"
  100.                 @context.invested = true
  101.     catch e
  102.         # the exception will be thrown if funds are not enough
  103.         if e.errorType == "InsufficientFunds"
  104.             error "insufficient funds: you have #{info.tradable_balance}"
  105.         else
  106.             throw e
  107.  
  108.     # TRADING
  109.     # if RSI_value > @context.OB
  110.     #     if cash > @context.eps * instrument.price
  111.     #         # open long position
  112.     #         #trading.buy instrument, "market", cash * (1.0 - @context.eps) / instrument.price
  113.     #         info "Bought #{instrument.asset()} with #{cash} at #{instrument.price}"
  114.     # else
  115.     #     if RSI_value < @context.OS && assets > @context.eps * instrument.price
  116.     #         #trading.sell instrument # close long position
  117.     #         info "Sold #{assets} #{instrument.asset()} at #{instrument.price}"
  118.  
  119. # Unlike orders, open positions don't get cancelled when the bot is stopped
  120. # the below snippet can be used to programmatically close it
  121. onStop: ->
  122.     instrument = @data.instruments[0]
  123.     pos = mt.getPosition instrument
  124.     if pos
  125.         debug "Closing position"
  126.         mt.closePosition instrument
  127.  
  128.  
  129. # this method is called upon restart
  130. onRestart: ->
  131.     debug "Restart detected"
  132.     # for example, we might need to cancel open orders
  133.     for o in mt.getActiveOrders()
  134.         mt.cancelOrder o
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement