Skip to content

Instantly share code, notes, and snippets.

@gabriel-dehan
Created October 11, 2017 14:20
Show Gist options
  • Save gabriel-dehan/ef5d3e97a6b63a3a7155da47258df091 to your computer and use it in GitHub Desktop.
Save gabriel-dehan/ef5d3e97a6b63a3a7155da47258df091 to your computer and use it in GitHub Desktop.
cryptotrader
# Some helpful API and implementation notes
# by: SimonSays
init: (context) -> #This si where we 'initialize' - this class is executed when the bot is first started or is restarted.
# This is where you set your variable initial values.
# The variable must start with context. (or if you choose another object definition. i.e. init: (c) -> works as well and requires c. prefix
#
# #We have three options for sending notifications to the trader log. Debug is black, info is Green and warn is Red
debug "Hello - welcome!"
info "This is an intro"
warn "To some basics of CryptoTrader!"
#
# For examples lets set a couple variables that we will use to set hard buy/sell prices
context.sellPrice = 11.00
context.buyPrice = 10.8
# In the examples i define some other variables. So that they can be passed between ticks and between order retries - we need to set them up here
context.tick = 0
context.order = false
serialize: (context) ->
#Serialization allows us to pass the variables within the init class to be passed tick to tick. This storage allows variables that have changed since trader initiation to be stored
# and passed back into the next tick upon trader restart. The CT system will sometimes restart traders without notice so this feature is required for things that change.
# since this script has nothing that needs changing - I am only passing the tick # as upon restart i do not want the tick to reset to 0 but rather keep on 'ticking'
#There are two methods of serialization - this is my personal preference as it allows me to neatly list all the variables I want to store. The other method is to use the storage function of the variable - see the API documentation for details
tick: context.tick
handle: (context, data)-># #The @handle is the class that is called and executed each tick recieved by the CT trader. Ticks are recieved at the time interval you choose (1m,5m,15m..etc)
# ins = data.instruments[0] #FIrst we must define the data set - per API documentation this is done with the data.instruments[0] call of the variable. This will return all the data we want from the tick
# #Note: i have used 'ins' here instead of 'instrument' this is to shorten the length of variables. The same can be done with context (i like having it as just 'c')
#
# # # instruments # # #
# Example data output from "data.instruments[0]"
#
# market : btce ##Trader market
# id : ltc_usd ##Trader pair
# period : 120 ##Trader period
# fee : 0.2 ##Trader fee
# open : ##Array of past and latest open price
# low : ##Array of past and latest low price
# high : ##Array of past and latest high price
# close : ##Array of past and latest close price
# volumes : ##Array of past and latest volumes
# pair : ltc,usd ##Pair being traded
# price : 11.125 ##current tick price
# volume : 23890.069 ##current tick volume
# ticker : ##This object cannot be directly called - I will explain what this is in a moment.
#
# You can call each of the above with ins.X where X is the object above.. i.e ins.market = btce and ins.open = candle open prices.
#
# For objects that are arrays containing ~1000 history values of data - you may call the most recent price with simply:
# ins.X[ins.X.length-1] where X is the object name above. ex: ins.open[ins.open.length-1] will return the latest open value.
#
# The ticker object may be called to obtain the latest ask and bid prices. In order to do this you can use the following syntax
# bidPrice = ins.ticker.buy
# askPrice = ins.ticker.sell
# ** The ticker object is updated in real time and can be called and updated within the tick. This is therefore available to you should you decided to do limit orders and want to re-evalulate your logic if a trade fails and retries.
#
# The example above can be seen for yourself by un-commenting the code and fixing indentation below:
# for own key, value of ins
# debug key + ' : ' + value
#
# Additional objects.
# ins.asset() ## outputs the fiat in the traded pair.. i.e USD or EUR
# ins.curr() ## outputs the currency in the traded pair.. i.e BTC or LTC
#
# # # Portfolio # # #
# We also have a portfolio handle that we can call to poll the api for the latest portfolio balance
# This is done with the following:
# cryptoBalance = (portfolio.positions[ins.asset()].amount)
# fiatBalance = portfolio.positions[ins.curr()].amount
# # # Ordering # # #
# So you have programmed logic and that logic takes in data, calculates indicators and has determined that an order is to be placed.
# There are two ways to submit an order - market and limit orders.
#
# The syntax for ordering is as follows:
# to buy: buy ins, amount, price, timeout
# to sell: sell ins, amount, price, timeout
#
# To buy 5 BTC @ 600 with a timeout of 122 seconds - the syntax would be:
# buy ins, 5, 600, 122
#
# If left undefined with 'null' default values will be assumed by CT.
# Defaults:
# amount: ALL of holding
# price: last price
# timeout: 30s
# Defaults are sent by:
# buy ins / sell ins
# buy ins,null,null,null / sell ins,null,null,null
#
# # # # Market Orders # # #
# Market orders are the default behavior of CT if not specific value is set. Market orders - on btce for example are NOT true market orders.
# On btce the market order default will place an order at the last price which is the same as ins.price.
# If the order times out, CT will cancel and resubmit the order at the latest last price. It will update the last price and resubmit until the order is fulfilled
#
# Market orders occur when the default price is sent - default indicated by 'null' OR by not defining specific variables.
# Default ordering:
# buy ins
# sell ins
# Ordering and defining variables
# buy ins, 5, null, 122
#
# # # # Limit Orders # # #
# Limit ordering sets the trade price at a specific value - like in the case above where we sought to buy @ 600.
#
# # # # How do I know I ordered successfully??? # # #
#
# Upon order completion CT will pass a 'true/false' through the ordering handle so placing the order placement in a boolean if block will allow us to determine if an order was successful.
#
# Ex:
# if buy ins,null,999,60 # this will attempt to spend all fiat at $999 and will timeout after 60 seconds.
# info " YAY I BOUGHT "
# else
# warn " OH NO - MY ORDER TIMED OUT"
#
# If you want to keep retrying upon timeout.. you can do a simple 'while' loop to retry the order - this would be for another lesson.
#
# # # INDICATORS # # #
#
# I won't go into great deal with indicators here and will instead reference you to Thanasis's code that lists ~100 available Talib indicators.
#
# Thanasis 100 indicator thread: https://cryptotrader.org/topics/203955/all-indicators-code
# Thanasis 100 indicator code: https://cryptotrader.org/backtests/XT4veDK5b7XpDu3g2
#
# # # EXAMPLE # # #
# # # # EXAMPLE 1 - Let's buy and sell at set prices # # #
context.tick++ # the ++ after a variable will interate it by one index.. i.e. 1,2,3,4,5,6 etc.
ins = data.instruments[0]
price = ins.price
# First let's define our account position by figuring out what our balances are
# Portfolio Balance #
cryptoBalance = (portfolio.positions[ins.asset()].amount)
fiatBalance = portfolio.positions[ins.curr()].amount
fiatMeans = fiatBalance/price #Since order amount is determined in crypto - if we want to buy with fiat we must place the order with the means available in fiat
equivBalance = cryptoBalance + fiatBalance/price
equivFiat = fiatBalance + cryptoBalance*price
# Let's debug the portfolio balance!
debug "Tick " + context.tick + " | Fiat: $" + fiatBalance.toFixed(2) + " | Crypto: " + cryptoBalance.toFixed(3) #.toFixed(x) sets the float (number of shown variables) to the value of x.
# Position - Let's determine if we are 'bought, sold or somewhere in the middle'
if equivBalance - cryptoBalance > 0.9*equivBalance #Logic to determine we are bought - which is defined as 90% or more in crypto (random value set for this example)
position = "OUT"
else if equivFiat - fiatBalance > 0.9*equivFiat #Logic to determine we are sold - which is defined as 90% or more in crypto (random value set for this example)
position = "IN"
else
position = "SPLIT" #IF we are not in or out - then we are somewhere in the middle right?
# Now lets act upon which position we are in. We may want to tailor our actions based on if we are all in fiat our all in crypto or somewhere in the middle.
# Place a sell if price is above a threshold and the bot is "IN" i.e bought in crypto
context.order = false # we have not ordered yet so setting the initial setting to false.
if ((position == "IN" or position == "SPLIT") && price > context.sellPrice) # Boolean logic checks if position is "IN" or "SPLIT" and if price is greater than the sell price.
if sell ins,cryptoBalance,price,null # We will place an order for entire balance
info "Order completed : Sell @ " + price
context.order = true
else if ((position == "OUT" or position == "SPLIT") && price < context.buyPrice)
if buy ins,fiatMeans,price,null
info "Order completed : Buy @ " + price
context.order = true
# Now lets send some updated stats if the order was successful
if context.order == true
cryptoBalance = (portfolio.positions[ins.asset()].amount)
fiatBalance = portfolio.positions[ins.curr()].amount
debug ". . Post Action Balance | Fiat: $" + fiatBalance.toFixed(2) + " | Crypto: " + cryptoBalance.toFixed(3) #.toFixed(x) sets the float (number of shown variables) to the value of x.
# you can also plot! its simple.
# you can plot a green or red dot @ a price with this code: - I'v e left this disabled for the code - remove the # to enable.
# plot
# buy: 11
# sell: 10.8
# if you want to plot a solid line - you can do this (i've left this enabled for the example)
plot
sell_limit: context.sellPrice
buy_limit: context.buyPrice
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment