Welcome to Read FMZ’s API documentation!¶
The main documentation for the site is organized into a couple sections:
1.1 Getting Started¶
FMZ is an automated trading platform for cryptocurrency traders with support for many bitcoin/eth/altcoin exchange markets. We has a complete tutorial for beginners, such as https://www.fmz.com/bbs-topic/3649 . Only need studying a couple of days, you are ready to code for your own robot.
What can FMZ do for me?
You can learn how to write your bots(strategies) from our strategies’ square which contains lots of open source code, share your strategy’s code with others, ask for professional help any time, run your strategy on any exchanges, contorl your bot on website with computer or cellphone, sell your strategies if you want, communicate with many other auto-trading lovers in our group. In a word, FMZ is a perfect platform for those who want do automated trading.
Which Cryptocurrency exchanges does FMZ support?
FMZ supports almost all exchanges that are popular, such as Binance, Bitfinex, Bitstamp, OKEX, Huobi, Poloniex,etc. you can also trade futures on OKEX and BitMEX. Check a full support list on 2.2.1 Add Exchange. You only need to write one strategy and run it on all exchanges without any changes.
What kinds of programming languages can I use to write my strategies?
FMZ supports JavaScript, Python, C++ (JavaScript and Python are recommended) for coding your strategies. Benefiting from the completed languages supporting(not a custom language only can be used for one platform), you can improve your programming skills as well as learn to write strategies.
What is the docker?
The docker is a program that runs on your own Internet Server, which in charge of the data request, data reception, network link, Log review etc. You can treat it like your strategy’s executor. Even if the FMZ server offline (breakdown, etc.), it will have no influence on your robot that is running. The Manager can run on variety of operating system. Such as Windows, Linux, Mac OS, Android, Raspbian, etc.
1.2 The Backtest System¶
What is backtest system? What it uses for?
When you completed a quantitative strategy, how do you know that the logic, amount and direction of profit of this strategy goes? Does it work? Apparently, we wouldn’t use the real money to test our strategies on the real market. But we could use the historical data to test it, see how it works out on the time, profit, and asset management in the past. It is winning or losing? How to use the Backtest System?
Does the number from the backtest system accurate? The results can be trusted?
FMZ divides the backtest system into real market level and simulation level. The real market level contains the whole completed historical data back testing.
The simulation level contains the k-lines data at regular intervals. Both level are based on the real market historical data. Only the real market level is more accurate and the results are more reliable.
The simulation level Backtest System explanation.
Notice that backtesting is the strategy only preform in the past. Historical data doesn’t represent the future. History may replay, it also may lead to the black swan. Please treat the backtest results reasonable and objectively.
1.3 FMZ Instruction Manual¶
If you are new to trading, you need to understand a few basic concepts:
KEY-WORD: “Futures”, “Spot”, “Stock”, “Position”, “Long”, “Short”, “Balance”, “Margin Call”, “Hedge”, “K Line”, “MACD”, “Ask / Bid”.
1.3.1 A quick look of the main page¶
After learning the most basic concepts, let’s start using FMZ to explore the quantitative world. (Building your own quantitative trading system is a very large project, you need to have considerable computer knowledge and skills, fortunately, FMZ has done this for you!)
Register your FMZ account,Log in to https://www.fmz.com.
First time to log in the website, it looks like this:

- 1.Your main control page
- 2.Manage all your bots (start,stop,delete,open,etc)
- 3.Manage all your strategies’ code
- 4.Deploy and manage your docker
- 5.Add new exchanges
- 6.Manual trading on the exchanges you added
- 7.Pay your bill
- 8.Ask any question here
- 9.FMZ’s simulated exchange
- 10.Debug tool where you can run a block of code without start a bot.
- 11.All kinds of message
- 12.Strategy square where open-source and charging strategies are listed
- 13.Live Robots where all live-running bots are listed.
- 14.Forums where you can post a post to discuss any question related.
- 15.Ask for someone to write code for you or provide this service for others.
- 16.Products for exchanges and agencies.
- 17.API documentation.
- 18.Some useful tools, check for yourself.
- 19.Your account information.
1.3.2 Deploy the docker¶
First of all, FMZ’s framework is very advanced, the user’s robot program (that is, the automated trading program) is running on the user’s own computer (of course, it can also be run on the cloud server), So, it’s very safe (don’t need worry about the FMZ website breakdown etc.), the user has direct control over the program.
Docker is a program that run your robots and communicate with FMZ website. You need to run a Docker first before start a real market robot.
Note
It is highly recommended to use the cloud server for runing program stably, such as Amazon or Google Cloud Server.
In the Dashboard page–Add docker
button, you can link to the download page https://www.fmz.com/m/add-node.

Here are steps to deploy the dockr in a Linux server(centOS 6):
- Buy a cloud server (VPS) from Amazon or Google, the lowest and cheapest configuration is enough. you may often has a free try for a long time.
- Login your server, fellow the instruction from your server provider or Google.
- Chose the docker that statisty your system version, most of the time, it is 64Bit.
- For
centos
, runwget 'http://q.fmz.net/dist/robot_linux_amd64.tar.gz'
, command not found? install firstyum install wget -y
. - Run
tar -xzvf robot_linux_amd64.tar.gz
to unzip. - Run
./robot -s rpcs@node.fmz.com:9902/xxxxxx -p yourFMZpassword
, you should see something like2018/07/05 05:04:10 Login OK, SID: 62086, PID: 7226, Name: host.localdomain
, which means everything is worked. rpcs@node.fmz.com:9902/xxxxxx
is unique to every users, find your own on https://www.fmz.com/m/add-node.- Now the docker isn’t run in the background, if you close the SHH client, the docker will stop.
- Press
ctrl + C
to stop the docker. - Run
nohup ./robot -s rpcs@node.fmz.com:9902/xxxxxx -p yourFMZpassword &
to run in the background. this step can also be done byScreen
command. - Check on https://www.fmz.com/m/dashboard, if everything is OK , you can find the docker deployed.
Steps to update the docker:
Note
If you want to keep the old docker, one server can run many dockers, just create a new folder and repeate the deploy steps.
- Stop all robots that run on the docker.
- Delete the docker from FMZ website. the docker will stop on your server too(don’t have to, you can run two dockers on one server, just create a new folder)
- Run
rm -rf robot_linux_amd64.tar.gz
in your dokcer files to delete the old docker. - Run
wget http://q.fmz.net/dist/robot_linux_amd64.tar.gz
to download the lastest docker. - Repeate the steps above.
- Change robot’s config to use the new docker, restart robots.

Note
One docker can run many robots, however, you can deploy more than one dockers on different server for speed or request-rate-limit consideration. the docker can be specified or auto-distributed when start a robot.
Warning
There are two public dockers for testing. don’t use them to run your robot on real market.
1.3.3 Add exchanges¶
Add your exchanges at this page: https://www.fmz.com/m/add-platform.
Now support:
Binance, Bitfinex, Huobi(huobipro), OKEX, Futures_OKCoin(OKEX), Futures_BitMEX, Poloniex, Bitstamp,
Wexapp(FMZ Simulation Exchange),AEX, BigONE, BitFlyer, Bithumb, Bitpie, Bittrex, CoinEx, CoinPlus,
Coincheck, Coinone, Futures_CTP, Futures_Deribit, Futures_Esunny, GateIO, HitBTC, KEX, Korbit,
Kraken, LiveCoin, OKCoin_EN, Quoine, WEX, ZB, Zaif.
Access Key
and Secret Key
is needed, you should apply on your exchange first.

Once the exchange is added, you can find it on Dashboard https://www.fmz.com/m/dashboard.

Note
New exchange supported is keep being added. you need to update the lastest docker to support new exchange.
1.3.4 Write or copy a strategy¶
Note
There are lots of details this docs doesn’t cover, you can explore by yourself, most of them are simple and clear. You can always post on our forum if you have any question.
Write your own strategy by clicking Add Strategy
.

You can choose different code languages and backtesting
For beginners, copy this strategy to begain: https://www.fmz.com/strategy/103070, which can be found on https://www.fmz.com/square.
Click Copy and backtest
:

Click Creat
:

Now your can find this strategy on your dashboard strategies list. https://www.fmz.com/m/dashboard
Edit your code here, don’t forget to save your code:

- 1.Edit your code
- 2.Backtesting, we will cover this part on an intermediate tutorial
- 3.The programer language of your code, JavaScript was used in this demo
- 4.The title, “|” splits Chinese and English title, which one will be showed is decided by the language of FMZ website
- 5.The type of your strategy, the default is common
- 6.The category of your strategy. You can divide your strategies into different categories if you have too many
- 7.Remote editing your code from your own IDE instead of our website
- 8.A link to the API doc
- 9.Notes of the strategy(only be seen by yourself). you can record the thoughts here.
- 10.Descriptions of the strategy. Others will see the descriptions if you share or sell your strategy on Square.
- 11.Manual of the strategy, can only be seen when someone bought your strategy.
- 12.Save your code, or
Ctrl+S
on edit mode. - 13.Save the backtesting config on the code.
- 14.Download the strategy file
- 15.Export and import the strategy while keeping all the parameters
- 16.Change the font size and edit the theme
- 17.Format the code automatically
- 18.Use VIM mode to edit.
Change and add global variables here:

1.3.5 Backtest your strategy¶
Click Stragegy name to strategy page.

Go to backtest page:

Add exchange and config your strategy:

Click Start Backtest
to start.
1.3.6 Run a robot on Wexapp¶
Wexapp is FMZ Simulation Exchange, which is basically the same as a real exchange but free of charge, you can run your robot on FMZ Simulation Exchange for testing your strategy.
First, you need to deposit assets on your simulation account on https://www.fmz.com/m/sandbox.

Click Add Robot
or https://www.fmz.com/m/add-robot to run a robot.
Config page as below:

You can find your robot is running on dashboard Now.

Go to robot page:
You can check the robot’s status and Logs, change the configs(need to stop robot first),

1.3.7 Charges Notes¶
0.125 RMB per robot per hour(around 0.018 USD).
robot run on FMZ Simulation Exchange(Wexapp) is free.

2.1 Typical Strategy structure¶
Strategy Coding currently support JavaScript, Python, C++, more programming tools supports under developing…
main()
as the entry function.onexit()
as the normal exit function, 5 minutes top run time. It can undeclared.onerror()
as the abnormal exit function, 5 minutes top run time. It can undeclared.init()
as the Initialization function, the strategy program will run it automatically at the beginning . It can undeclared.
Example of a basic strategy fame:
function onTick(){
//write your strategy here, it will repeat itself
}
function main(){
while(true){
onTick();
Sleep(60000);
}
}
}
For example, if You want buy one amount of order at the price 100 every second. It can be written like this:
function onTick(){
exchange.Buy(100,1);
}
function main(){
while(true){
onTick();
Sleep(1000);//Pause time is optional, Units are Millisecond(1 second = 1000ms)
}
}
2.2 Exchange¶
Every API method is called by exchange object, such as exchange.GetTicker()
, exchange.Buy()
.
Exchange and trade pair is set when you start a robot. The following market api and trade api is based on this setting.
If you set your exchange is “Binance”, trading pair is “BTC_USDT”, then call exchange.GetTicker()
, you will get the ticker of “BTCUSDT” of Binance.
trading pair is also called symbol
or currency
in some exchenge’s API docs,
2.2.1 Add Exchange¶
Check on how to add exchange when start a robot: 1.3.3 Add exchanges
Now support:
AEX
BigONE
Binance
BitFlyer
Bitfinex
Bithumb
Bitpie
Bitstamp
Bittrex
BotVS
CoinEx
CoinPlus
Coincheck
Coinone
Exchange
Futures_BitMEX
Futures_CTP
Futures_Deribit
Futures_Esunny
Futures_OKCoin
GateIO
HitBTC
Huobi
KEX
Korbit
Kraken
LiveCoin
OKCoin_EN
OKEX
Poloniex
Quoine
STEX
WEX
ZB
Zaif
2.2.2 Exchange Variable¶
exchange
It can be imaged as a real exchange; default setting is the first exchange in your strategy’s parameter. all of data interactive with the exchange which achieve through this object function.
exchanges
The exchange’s array, it contains multiple exchange objects which are sorted by order of addition . used as exchanges[0]
, exchange[1]
etc…
Note
If you use exchange
directly, which equals to exchanges[0]
.
When you add an exchange, it’s always fllowed by a trade pair, such as BTC_USDT
, so
exchanges[0]
and exchanges[1]
can be the same “actually exchange” but with different trade pair.
2.2.3 Exchange Information¶
GetName
exchange.GetName()
Return the name of the exchange, string type
GetLabel
exchange.GetLabel()
Return the exchange’s custom label, string type
2.2.4 FMZ Simulation Exchange¶
FMZ Simulation Exchange is basically the same as a real exchange, you can run your robot on FMZ Simulation Exchange for testing your strategy, which is totally free. check it on https://wex.app, and deposit some money or bitcoin to start
2.3 Market API¶
The following functions is used for get market inforamtion of exchange,
which are called from object exchange
or exchanges[x]
,for example:exchange.GetTicker()
or exchanges[0].GetTicker()
means return the market quotations.
Warning
When calling any API function that accesses the exchange API (such as GetTicker()
, Buy()
, CancelOrder()
, etc…), it may get access failure due to exchange server problem, the network transmission problem, and so on.
In this case, GetTicker()
will return null
, which may cause the stop of your programe. a JavaScript example to do fault tolerance as below.
var ticker = exchange.GetTicker()
if(ticker == null){
// Retry, or other processing logic.
}
A deflaut retry function is _C()
2.3.1 GetTicker¶
exchange.GetTicker()
Get the current market quotations.
Return value: Ticker structure
The Ticker structure contains the following variables:
Field | Type | Description |
---|---|---|
Info | Object | the original data returned by the exchange |
High | Number | Highest price |
Low | Number | lowest price |
Sell | Number | the latest selling price, also called bidPrice |
Buy | Number | the latest buying price, also called askPrice |
Last | Number | last traded price |
Volume | Number | most recent trading volume |
OpenInterest | Number | net position(only for features) |
Example ticker from binance:
{
"Info":{
"highPrice":"6173.01000000",
"openTime":1530152780326,
"firstId":53572675,
"lastId":53735989,
"count":163315,
"priceChange":"-266.96000000",
"weightedAvgPrice":"6035.81831943",
"bidPrice":"5871.63000000",
"openPrice":"6139.00000000",
"closeTime":1530239180326,
"lowPrice":"5827.00000000",
"quoteVolume":"197096315.23211791",
"priceChangePercent":"-4.349",
"prevClosePrice":"6139.00000000",
"lastQty":"0.25866000",
"bidQty":"0.00300000",
"askPrice":"5872.05000000",
"symbol":"BTCUSDT",
"lastPrice":"5872.04000000",
"askQty":"0.07344000",
"volume":"32654.44796400"
},
"High":6173.01,
"Low":5827,
"Sell":5872.05,
"Buy":5871.63,
"Last":5872.04,
"Volume":32654.447964,
"OpenInterest":0,
"Time":1530239180443
}
A JavaScript example using the variables in the Ticker structure:
function main(){
var ticker = exchange.GetTicker();
Log("High:", ticker.High, "Low:", ticker.Low, "Sell:", ticker.Sell)
}
For Python the code is basically the same:
def main():
ticker = exchange.GetTicker()
Log("High:", ticker.High, "Low:", ticker.Low, "Sell:", ticker.Sell)
Note
If you use the a number in Info
directly, make sure the data type is float.
- For JavaScript:
var priceChange = praseFloat(ticker.Info.priceChange);
- For Python:
priceChange = float(ticker.Info["priceChange"])
.
2.3.2 GetDepth¶
exchange.GetDepth()
Get the exchange order book.
Return value: Depth structure
The Depth structure contains the following variables:
Field | Type | Description |
---|---|---|
Asks | Array | the array of asks,from low to high by price |
Bids | Array | the array of bids,from high to low by price |
Time | Number | the timestamp of request |
The Asks and Bids structure contains the following variables:
Field | Type | Description |
---|---|---|
Price | Number | the pirce of ask or bid |
Amount | Number | the amount of ask or bid |
Example depth from binance:
{
"Info":null,
"Asks":[
{"Price":5866.38,"Amount":0.068644},
{"Price":5866.39,"Amount":0.263985},
{"Price":5866.73,"Amount":0.05},
{"Price":5866.77,"Amount":0.05},
{"Price":5867.01,"Amount":0.15},
{"Price":5875.89,"Amount":0.05},
......
]
"Bids":[
{"Price":5865.13,"Amount":0.001898},
{"Price":5865,"Amount":0.085575},
{"Price":5864.15,"Amount":0.013053},
{"Price":5863.65,"Amount":0.016727},
{"Price":5863.51,"Amount":0.128906},
{"Price":5863.15,"Amount":0.2}
......
],
"Time":1530241857399
}
A useful JavaScript example using depth:
function main(){
var depth = exchange.GetDepth();
var price = depth.Asks[0].Price;
var amount = depth.Asks[0].Amount;
if(amount > 10){
exchange.Buy(price, 10);
}
}
Note
GetDepth()
doesn’t return real depth at backtesting.
2.3.3 GetTrades¶
exchange.GetTrades()
Get Exchange Trading History.(not your trading history)
Return value: Array of Trade Structure
Note
Some exchanges do not support this method, the number of return data depends on exchanges.
The Trade structure contains the following variables:
Field | Type | Description |
---|---|---|
Time | Number | Unix timestamp of the trade time |
Price | Number | price of the trade |
Amount | Number | amount of the trade |
Type | Order Type | Order Type Constant |
Order Type is global constant, you can take ORDER_TYPE_BUY
as 0
:
Global constant | Meaning | Value |
---|---|---|
ORDER_TYPE_BUY | buy order | 0 |
ORDER_TYPE_SELL | sell order | 1 |
Example trades from binance:
[
{"Id":47317269,"Time":1530244709886,"Amount":0.002902,"Price":5884.38,"Type":1},
{"Id":47317270,"Time":1530244709886,"Amount":0.082102,"Price":5884.78,"Type":1},
{"Id":47317271,"Time":1530244713111,"Amount":0.122439,"Price":5884,"Type":0},
.....
{"Id":47317278,"Time":1530244717131,"Amount":0.000029,"Price":5884,"Type":0},
]
A useful JavaScript example using trades:
function main(){
while(true){
var trades = exchange.GetTrades();
for(var i=0;i<trades.length;i++){
if(trades[i].Type == ORDER_TYPE_BUY && trades[i].Amount > 100){
Log("Big amount buy order","time:", trades[0].Time, "Price:", trades[0].Price, "Amount:", trades[0].Amount);
}
}
Sleep(3000)//sleep 3 seconds
}
}
Warning
The trades in simulation backtesting is empty.
2.3.4 GetRecords¶
exchange.GetRecords(period)
exchange.GetRecords()
Get Exchange’s history K lines/Candlesticks data.
Parameter period
: K lines cycle, Optional Parameters, default K line cycle is set when start the robot.
All available values:
PERIOD_M1 : 1 minute,
PERIOD_M5 : 5 minutes,
PERIOD_M15 : 15 minutes,
PERIOD_M30 : 30 minutes,
PERIOD_H1 : 1 hour,
PERIOD_D1 : one day.
Return value: Record structure array. from old to recent by time.
The Record structure contains the following variables:
Field | Type | Description |
---|---|---|
Time | Number | Unix timestamp of the kline |
Open | Number | open price of the kline |
High | Number | highest price of the kline |
Low | Number | lowest price of the kline |
Close | Number | close price of the kline |
Volume | Number | trading volume |
Example Records from binance:
[
{"Time":1526616000000,"Open":7995,"High":8067.65,"Low":7986.6,"Close":8027.22,"Volume":9444676.27669432},
{"Time":1526619600000,"Open":8019.03,"High":8049.99,"Low":7982.78,"Close":8027,"Volume":5354251.80804935},
{"Time":1526623200000,"Open":8027.01,"High":8036.41,"Low":7955.24,"Close":7955.39,"Volume":6659842.42025361},
......
]
A useful JavaScript example using Records to get a close array:
function main(){
var close = [];
var records = exchange.GetRecords(PERIOD_H1);
for(var i=0;i<records.length;i++){
close.push(records[i].Close);
}
}
Note
- The K-lines data will accumulate over time, accumulating up to 2000, then will update one record at one K-line cycle, and delete the earliest one at the same time.
- If the exchange provides a K-line API. In this case, the data is obtained directly from the exchange.
- If the exchange does not provide a K-line API. your robot will using
GetTrades()
function to generate K-line each time the user calls GetRecords.In this case,Records length will be one when first start.
2.4 Trade API¶
The following functions is used for trading,
which are called from exchange
or exchanges[x]
object, for example: exchange.Sell(100, 1)
;
Send a buy order to the exchange with the price is 100, and the quantity is 1.
If you want change the trading pair before trade, check on exchange.IO("currency", symbol)
2.4.1 GetAccount¶
exchange.GetAccount()
Get exchange account information
Return value: Account structure
The Account structure contains the following variables:
Field | Type | Description |
---|---|---|
Info | Object | The original data returned by the exchange |
Balance | Number | Balance (Pricing currency balance, BTC if your trading pair is ETH_BTC ) |
FrozenBalance | Number | Frozen balance in your pending buy orders |
Stocks | Number | The available quantity of trading currency, ETH if your trading pair is ETH_BTC |
FrozenStocks | Number | Frozen Stocks in your pending sell orders |
Example of GetAccount from binance, trading pair is BTC_USDT
:
{
"Stocks":0.38594816,
"FrozenStocks":0,
"Balance":542.858308,
"FrozenBalance":0
"Info":{
"takerCommission":10,
"canTrade":true,
"canDeposit":true,
"updateTime":1530330645991,
"balances":[
{"asset":"BTC","free":"0.38594816","locked":"0.00000000"},
{"asset":"LTC","free":"0.00736000","locked":"0.00000000"},
{"asset":"ETH","free":"2.44434439","locked":"0.00000000"},
{"asset":"BNC","free":"0.00000000","locked":"0.00000000"},
{"asset":"ICO","free":"0.00000000","locked":"0.00000000"},
......
]
"makerCommission":10,
"buyerCommission":0,
"sellerCommission":0,
"canWithdraw":true
},
}
A useful JavaScript example of Log your account value for a certain trading pair:
function main(){
while(true){
var ticker = exchange.GetTicker();
var account = exchange.GetAccount();
var price = ticker.Buy;
var stocks = account.Stocks + account.FrozenStocks;
var balance = account.Balance + account.FrozenBalance;
var value = stocks*price + balance;
Log('Account value is: ', value);
Sleep(3000);
}
}
2.4.2 Buy¶
exchange.Buy(Price, Amount)
Send a buy order, return an order ID
Parameter
Price : order price, number type
Amount : order quantity, number type
Return
order id, number type
Tip
If the exchange’s order API support market orders, use exchange.Buy(-1, 0.1)
, if your trading pair is ETH_BTC
,
which means buy 0.1 ETH at market price. Be carefully when using market order.
A useful JavaScript example of Buy for buy certain amount of bitcoin at a certain price:
function main(){
while(true){
var ticker = exchange.GetTicker();
var price = ticker.Buy;
if(price >= 7000){
exchange.Buy(price, 10);
}
Sleep(3000);
}
}
2.4.3 Sell¶
exchange.Sell(Price, Amount)
Send a sell order, return an order ID
Parameter
Price : order price, number type
Amount : order quantity, number type
Return
order id, number type
Tip
If the exchange’s order API support market orders, use exchange.Sell(-1, 0.1)
, if your trading pair is ETH_BTC
,
which means sell 0.1 ETH at market price.
2.4.4 CancelOrder¶
exchange.CancelOrder(orderId)
Cancel an order by order id.
Parameter
orderId : order id, returned by Buy or Sell API.
Return value: bool type
true
means that the cancellation of the order request was successful.
false
means cancellation of the order request failed. (It is only a successful request.
Whether the exchange cancels the order, it is best to call exchange.GetOrders()
.)
A JavaScript example of cancel an order after some time:
function main(){
var id = exchange.Sell(99999, 1);
Sleep(3000);
exchange.CancelOrder(id);
}
2.4.5 GetOrder¶
exchange.GetOrder(orderId)
Get order details by order id.
Parameter
orderId : order id, returned by Buy or Sell API.
Return value: Order structure
The Order structure contains the following variables:
Field | Type | Description |
---|---|---|
Info | Object | The original data returned by the exchange |
Id | Number | Unique ticket identifier |
Price | Number | Order price |
Amount | Number | Order quantity |
DealAmount | Number | The deal amount of this order |
AvgPrice | Number | Average transaction price (0 means the exchange do not return this field) |
Status | Const | Order Status |
Type | Const | Order Type, ORDER_TYPE_BUY : Buy Order, ORDER_TYPE_SELL : Sell Order |
Order Status is global constant:
Global constant | Meaning | value |
---|---|---|
ORDER_STATE_PENDING | Incomplete | 0 |
ORDER_STATE_CLOSED | Completed | 1 |
ORDER_STATE_CANCELED | Canceled | 2 |
Order Type is global constant:
Global constant | Meaning | value |
---|---|---|
ORDER_TYPE_BUY | BUY | 0 |
ORDER_TYPE_SELL | SELL | 1 |
Example of GetOrder from binance:
{
"Id":125723661,
"Amount":0.01,
"Price":7000,
"DealAmount":0,
"AvgPrice":0,
"Status":0,
"Type":1,
"ContractType":"",
"Info":{
"side":"SELL",
"stopPrice":"0.00000000",
"timeInForce":"GTC",
"type":"LIMIT",
"time":1530325939498,
"orderId":125723661,
"clientOrderId":"H3R333f47MsFrahQUsa8egU",
"origQty":"0.01000000",
"status":"NEW",
"executedQty":"0.00000000",
"isWorking":true,
"symbol":"BTCUSDT",
"price":"7000.00000000",
"icebergQty":"0.00000000"
}
}
A JavaScript example of using this API, which will buy until your account has 10 coins:
function main(){
while(true){
var amount = exchange.GetAccount().Stocks;
var ticker = exchange.GetTicker();
if(10-amount>0.01){
var id = exchange.Buy(ticker.Sell, Math.min(10-amount,1));
}else{
return;
}
var status = exchange.GetOrder(id).Status;
if(Status == ORDER_STATE_PENDING){
exchange.CancelOrder(id);
}
Sleep(3000);
}
}
Note
Buy
, Sell
, CancelOrder
, can be followed by some additional output parameters, such as: exchange.Buy(price, amount, 'BTC_USDT')
,
exchange.CancelOrder(orderId, 'BTC_USDT')
, Which will give you extra information in robot Logs.
2.4.6 GetOrders¶
exchange.GetOrders()
Get all Current open orders for your trading pair.
Return value: Order structure array
Example of GetOrders from binance, the trading pair is YOYOETH
:
[
{
"Info":{
"executedQty":"0.00000000",
"type":"LIMIT",
"isWorking":true,
"price":"0.00012826",
"status":"NEW",
"timeInForce":"GTC",
"symbol":"YOYOETH",
"side":"SELL",
"stopPrice":"0.00000000",
"icebergQty":"0.00000000",
"time":1530331666316,
"orderId":16387538,
"origQty":"1123.00000000",
"clientOrderId":"TrKOsaHcqc667tjZQtg09b"
},
"Id":16387538,
"Amount":1123,
"Price":0.00012826,
"DealAmount":0,
"AvgPrice":0,
"Status":0,
"Type":1,
"ContractType":""
}
]
A JavaScript example of using this API, which will cancel all open orders for set trading pair:
fuction CancelAll(){
var orders = exchange.GetOrders();
for(var i=0;i<orders.length,i++){
exchange.CancelOrder(orders[[i].Id);
}
}
function main(){
CancelAll();
while(true){
//do something
Sleep(10000);
}
}
2.4.7 SetContractType¶
exchange.SetContractType(ContractType)
Set contract type for futures trade. must be set first before using other API.
Parameter value: string type
OKEX futures have “this_week”, “next_week”, “quarter” three parameters
exchange.SetContractType("this_week"); // Set to Weekly Contract
2.4.8 GetPosition¶
exchange.GetPosition()
Get the current position information, only for Futures trade. OKEX can pass a parameter, specify the type of contract to get.
Return value: position array
BTC Futures support: OKEX
, BitMEX
.
The position structure contains the following variables:
Field | Type | Description |
---|---|---|
Info | Object | The original data returned by the exchange |
MarginLevel | Number | Leverage size, OKEX is 10 or 20, full amount of okex futures margin mode returns a fixed 10, because the original API does not support |
Amount | Number | ositions, OKEX indicates the number of contracts (integer and greater than 1) |
FrozenAmount | Number | Position freeze |
Price | Number | Average price of positions |
Profit | Number | Order Status |
Type | Const | PD_LONG is a long position, PD_SHORT is a short position. |
ContractType | String | Contract name |
Postion Type is global constant:
Global constant | Meaning | value |
---|---|---|
PD_LONG | long | 0 |
PD_SHORT | short | 1 |
A JavaScript example:
function main(){
exchange.SetContractType("this_week") //for OKEX future
var position = exchange.GetPosition()
if(position.length>0){
Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount, "Price:",
position[0].Price, "Profit:", position[0].Profit, "Type:", position[0].Type, "ContractType:", position[0].ContractType)
}
}
2.4.9 SetMarginLevel¶
exchange.SetMarginLevel(MarginLevel)
Set the leverage size, only for Futures trade.
Parameter value: number integer
Set the leverage size of Buy or Sell. MarginLevel has 5, 10, 20 optional parameters. OKEX supports 10 times and 20 times. For example:
exchange.SetMarginLevel(10)
2.4.10 SetDirection¶
exchange.SetDirection(Direction)
Set Buy or Sell Order Types, only for Futures trade.
Parameter value: string type, can be buy
, closebuy
, sell
, closesell
.
A JavaScript example:
function main(){
exchange.SetContractType("this_week");
exchange.SetMarginLevel(5); // Set the leverage to 5 times
exchange.SetDirection("buy"); // Set the order type to buy long
exchange.Buy(1000, 2); //buy long at the price 1000, quantity of 2
exchange.SetDirection("closebuy");
exchange.Sell(1000, 2); //close long position
}
2.5 Extended API¶
The following functions is used for extending your API. Most of the time, your code can be wrote by the API above.
2.5.1 IO¶
exchange.IO() has different usages depends on parameters.
Change trading pair
exchange.IO("currency", symbol)
Parameter value: symbol
, trading pair to switch.
Example:exchange.IO("currency", "LTC_USDT")
, which will switch the default trading pairs configured by the robot when it was created to LTC_USDT
.
A JavaScript example of using IO
to trade several trading pairs:
var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT", "BCC_USDT"];
var buyValue = 1000;
function main(){
for(var i=0;i<symbols.length;i++){
exchange.IO("currency", symbols[i]);
var ticker = exchange.GetTicker();
var amount = _N(buyValue/ticker.Sell, 3);
exchange.Buy(ticker.Sell, amount);
Sleep(1000);
}
}
Change exchange base API address
exchangs.IO("base", baseAddress)
Parameter value: baseAddress
, exchange base API address to switch.
If an exchange change it’s base API address, you can use this function to change the base address temporarily till FMZ change it.
In some case, changing the address can acess another part of a exchange, such as huobipro and hadax,
their API is the same, just switching the base address you can trade on hadax.
exchange.IO("base", "https://api.hadax.com")
Use exchange’s orgin API
exchange.IO("api", httpMethod, resource, params)
Acesss to exchange’s other API.
Note
Only used for those API methods needed secret key to sign, other methods can be acessed by HttpQuery(url)
function.
Using this function requires the understanding of exchange’s orgin API, it extend the functionality that the FMZ does not add (to submit a POST request without having to worry about the parameter encryption process, the FMZ has completed the encryption already, just need fill in the corresponding parameters). For example, the FMZ platform does not currently support margin leverage trading on bitfinex exchanges. We can implement this function by using the IO function.
- First find bitfinex API description webpage: bitfinex.
- Then we know that the order is interacting with a POST request, so we pass the parameter httpMethod to the order address of the “POST” margin transaction: ‘ https://api.bitfinex.com/v1/order/new ‘. Because the FMZ has internally specified the root address, we only need to pass the value of the parameter resource to “/v1/order/new”.
- Then the params parameter is not filled in. The params variable represents the information to be exchanged. We can send all kinds of information with the “&” symbol to send them. We first go to bitfinex to see that the next buy or sell order requires 5 parameters., they are: symbol, amount, price, side, type. We assign these five parameters respectively. If we want to buy Litecoin LTC, the quantity is 1, the price is 10, and the margin trading mode, then we can construct such a string: “symbol=ltc&amount=1&price=10&side=buy&type= Limit”.
The final JavaScript code:
function main(){
exchange.IO("api","POST","/v1/order/new","symbol=ltc&amount=1&price=10&side=buy&type=limit");
}
An OKEX Example:
function main(){
var ret = exchange.IO("api", "POST", "/api/v1/future_position.do", "symbol=eth_usd&contract_type=this_week");
Log(ret);
}
2.5.2 Go¶
exchange.Go(Method, Args)
Multi-threaded asynchronous support functions that can convert the operations of all supported functions into asynchronous concurrency.
Parameter value:
Method : a function name.
Args : the args of method.
Supported Functions: GetTicker
, GetDepth
, GetTrades
, GetRecords
, GetAccount
, GetOrders
, GetOrder
, CancelOrder
, Buy
, Sell
, GetPosition
robot thread must obtain the result from the wait function, the docker automatically releases the thread resource requested through the Go function. If the return result of the wait function is not obtained, the thread resource will not be automatically released, which will cause threads to accumulate, and more than 2000 will report an error. “too many routine wait, max is 2000”
A JavaScript example
function main(){
var a = exchange.Go("GetTicker"); //GetTicker Asynchronous multithreaded execution
var b = exchange.Go("GetDepth");
var c = exchange.Go("Buy", 1000, 0.1);
var d = exchange.Go("GetRecords", PERIOD_H1);
// The above four operations are concurrent multi-threaded asynchronous execution, will not be time-consuming and immediately return
var ticker = a.wait(); // Call wait method wait for return to asynchronous get ticker result
var depth = b.wait(); // Return depth, it is also possible to return null if it fails
var orderId = c.wait(1000); // Return the order number, limit 1 second timeout, timeout returns undefined, this object can continue to call wait until the last wait timeout
var records = d.wait(); // Wait for K-line result
var ret = d.wait(); // Here waits for an asynchronous operation that has waited and ended, returns null, and logs an error message.
}
The difference between Python and JavaScript, Python’s wait returns two parameters, the first is the result of the asynchronous API, and the second is whether the asynchronous call is completed.
ret, ok = d.wait(); // Ok is bound to return true unless the strategy is stopped
ret, ok = d.wait(100); // Ok returns False, waits for a timeout, or waits for an instance that has ended
Note
This function only creates multi-threaded execution tasks when it runs on a real market. Backtesting does not support multithreaded concurrent execution of tasks (backtesting is available, but it is also performed sequentially).
2.5.2 GetRawJSON¶
exchange.GetRawJSON()
Returning of the original content (string) that returned by the last REST API request, which can be used to resolve extension information on its own.
There are a lot of inforamtions in the raw data returned from exchange, part of them are in Info
Field, if not, you can use this API.
Return value : string type
A JavaScript example of using GetRawJSON and parse the raw data:
function main(){
exchange.GetAccount();
var obj = JSON.parse(exchange.GetRawJSON());
Log(obj);
}
2.5.4 GetCurrency¶
exchange.GetCurrency()
Returns the name of the currency pair operated by the exchange.
Return value: string type
2.5.5 GetQuoteCurrency¶
exchange.GetQuoteCurrency()
Returns the base currency name of the exchange operation, eg BTC_CNY returns CNY, ETH_BTC returns BTC.
Return value: string type
2.5.6 SetPrecision¶
exchange.SetPrecision(PricePrecision, AmountPrecision)
Set the decimal precision of price and type order quantity, and will automatically truncate after setting.
If you use exchange.Sell(7000.1225,1.223123)
on Bianace directly, which will return error {"code":-1013,"msg":"Filter failure: PRICE_FILTER"}
.
that’s why you should care about precision.
You can also use _N()
function as exchange.Sell(_N(price,2), _N(amount,5))
You can find the demands of precision and others in exchange’s docs, for example: https://api.binance.com/api/v1/exchangeInfo
Parameter value:
PricePrecision
, number type, used to control the decimal point of the price.
AmountPrecision
, number type, used to control the decimal point of the amount.
exchange.SetPrecision(2, 3);
function main(){
exchange.Sell(7000.1225,1.223123) //which will be the same as exchange.Sell(7000.12,1.223)
}
Note
SetPrecision doesn’t work in backtesting
2.5.7 GetRate¶
exchange.GetRate()
Returning of the exchange rate that between the exchange currency and the current display currency. Returning 1 means currency conversion is not allowed.
Return value: number type
Note
If you do not call exchange.SetRate() to set the conversion rate, GetRate defaults to the exchange rate value of 1, ie, the current displayed denomination currency has not been converted.
2.5.8 SetRate¶
exchange.SetRate(scale)
Parameter value: scale
, number type
Return value: number type
If you use exchange.SetRate() to set an exchange rate value, such as 0.85(the rate of EUR and USD), then all exchange prices, depth, order price and all other price information in the current exchange currency represented by the exchange object will be multiplied by the setting.
2.5.8 SetProxy¶
exchange.SetProxy()
Switch to Proxy Server to Access Exchange
Each exchange object (exchanges[n]) can set up an agent. After setting up the agent, the access exchange API will be accessed through the agent.
// Take the exchange of the main exchange object as the first added exchange object, ie: exchanges[0] as an example.
exchange.SetProxy("socks5://127.0.0.1:8889") // Set proxy, no username, no password.
exchange.SetProxy("socks5://username:password@127.0.0.1:8889") // Set up the proxy, enter the username and password
exchange.SetProxy("") // Switch to normal mode without using a proxy.
2.5.9 SetTimeout¶
exchange.SetTimeout(time)
Set timeout for exchange’s rest request.
Only the REST request is used to set the timeout time.
For example: exchange.SetTimeout(3000)
, set the exchange exchange object, send a rest request starts timing, exceeds 3 seconds, timeout returns null.
exchange.SetTimeout()
2.5.10 Log¶
exchange.Log(logType, orderId, price, amount)
Doesn’t actually sent the order, just record order information for testing your strategy.
Parameter values:
logType : LOG_TYPE_BUY, LOG_TYPE_SELL, LOG_TYPE_CANCEL
orderId : order id, customizable an incremental value
price : price
amount : quantity
Return value: number type
Note
This function is a function of the exchange exchange object, which is different from the global function Log().
2.6 Global Function¶
2.6.1 Log¶
Log(message)
Save a message to the robot logs.
Parameter value: message can be any type.
Log(123);
Log('hello', 'world', 123);
Log("red color message", "#FF0000");
Log("blue color message#FF0000");
Log supports pushing message to your WeChat account.
adding the @ character to the string, the message will go to the push queue and be pushed to the WeChat account that uses the binding (bind in account security) (50/hour, 1/5 second limit)
Log("hello Wechat!@");
Log supports base64-encoded pictures print:
Log("`data:image/png;base64,AAAA`");
Log supports Python matplotlib.pyplot object print directly.
as long as the object contains savefig
method, such as:
import matplotlib.pyplot as plt
def main():
plt.plot([3,6,2,4,7,1])
Log(plt)
Log supports present message’s character or background with custom color:
Change message’s character color: message need end with RGB color code such as ##FF0000
, for more RGB color, check on https://www.w3schools.com/colors/colors_picker.asp.
Change message’s background color: message need end with like #FF0000CC3299
,the last six number CC3299
represnt the RGB color code.
Log("red color message", "#FF0000");
Log("blue color message#FF0000CC3299");
2.6.2 LogStatus¶
LogStatus(Msg)
This kind of Log information is displayed above the log and update every time when it is called.
Parameter value: Msg can be any type.
LogStatus(" This is a normal status prompt");
LogStatus(" This is a red font status prompt #ff0000");
LogStatus(" This is a multi-line status message\n I'm the second line");
Like Log()
function, LogStatus
supports base64-encoded images and Python matplotlib.pyplot object.
LogStatus can Log tables on your robot page.
Log a table example, add `
characters to both sides and treat it as a complex message format (currently supported table).
var table = {type: 'table', title: ' Account information support color #ff0000', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]};
LogStatus('`' + JSON.stringify(table)+'`');
Another example, information can also appear in multiple lines:
LogStatus("First line message\n" + JSON.stringify(table)+"`\n third line message");`
Log multiple tables in a group, switching by TAB:
var table1 = {type: 'table', title: ' Account information 1', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]};
var table2 = {type: 'table', title: ' Account information 2', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]};
LogStatus('`' + JSON.stringify([table1, table2])+'`'); // Supports multiple tables to be displayed at the same time and will be displayed in a group with TAB
Log multiple tables in one page:
function main(){
var tab1 = {type : "table",title : "Table 1",cols : ["1", "2"],rows : []};
var tab2 = {type : "table",title : "Table 2",cols : ["1", "2", "3"],rows : []};
tab1.rows.push(["jack", "lucy"]);
tab2.rows.push(["apple", "pen", "apple pen"]);
LogStatus('`' + JSON.stringify(tab1) + '`\n' + '`' + JSON.stringify(tab2) + '`');
}
Log table with a button in the table. The strategy uses GetCommand
to receive the contents of the cmd property.
var table = {
type: 'table',
title: 'Positioning operations',
cols: ['Column 1', 'Column 2', 'Action'],
rows: [
['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': 'Close the position'}],
]
};
LogStatus('`' + JSON.stringify(table) + '`')
// Or construct a separate button
LogStatus('`' + JSON.stringify({'type':'button', 'cmd': 'coverAll', 'name': ' Close the position'}) + '`')
// Can customize button styles (bootstrap button properties)
LogStatus('`' + JSON.stringify({'type':'button', 'class': 'btn btn-xs btn-danger', 'cmd': 'coverAll', 'name': 'close the position'}) + '`')
2.6.3 LogProfit¶
LogProfit(Profit)
Record profit value, draw a line chart in your robot page, will remain after you restart your robot.
Parameter value: profit , number type
A useful JavaScript example of Log Profit for a certain trading pair:
function GetValue(){
var ticker = exchange.GetTicker();
var account = exchange.GetAccount();
var price = ticker.Buy;
var stocks = account.Stocks + account.FrozenStocks;
var balance = account.Balance + account.FrozenBalance;
var value = stocks*price + balance;
return value;
}
function main(){
var initValue = GetValue();
var profit = 0;
while(true){
profit = GetValue() - initValue;
LogProfit(profit);
Sleep(60000);//sleep one minute
}
}
Note
LogProfit
doesn’t have to be recording the profit , it can be any number you like to present, such as total account value, free USDT amount.
Profit
is calculated by your own.
2.6.4 SetErrorFilter¶
SetErrorFilter(RegEx)
Error message filtering
Parameter value: string type
Errors that are matched by this regular expression will not be uploaded to the log system. Multiple set (filtered logs, database files corresponding to robot IDs in the logs/robot under the docker directory can be called multiple times to prevent frequent errors Causes database file expansion.)
SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused");
2.6.5 LogReset¶
LogReset()
Clear the log, you can pass a parameter, specify the number of recent logs to keep, clear the rest of the log.
2.6.6 LogProfitReset¶
LogProfitReset()
Clear all history logs, can take a number parameter, specify the number of reservations.
2.6.7 EnableLog¶
EnableLog(IsEnable)
Turn on or off logging of orders and error messages/
Parameter value: isEnable is bool type
2.6.9 GetLastError¶
GetLastError()
Get the latest error message, generally do not need to use, because the program will automatically upload the error message to the log system.
Return value: string type
2.6.10 GetCommand¶
GetCommand()
Get Interactive Command (utf-8).
Get the command sent from the strategy interactive interface and clear it. If there is no command,
it will return null
. The returned command format is “Button name: parameter”. If there is no parameter, the command is the button name.
A JavaScript example
function main(){
while(true) {
var cmd = GetCommand();
if (cmd) {
Log(cmd);
}
Sleep(1000);
}
}
2.6.11 Sleep¶
Sleep(Millisecond)
Pause the robot program for a period of time.
Parameter value: Millisecond is number type
Sleep(1000)
means sleep 1 second.
Warning
In almost all the situation, Sleep
is necessary in while
loops, otherwise you may exceed the exchange’s API rate limits of REQUESTS.
2.6.12 IsVirtual¶
IsVirtual()
Your robot is runing in a simulated backtest or not.
Return value: bool type, Simulate back test state return true, the real market returns false
2.6.15 Mail¶
Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)
Send a e-mail.
Parameter values: all are string types
Return value: bool type, return true if successful
function main(){
Mail("smtp.163.com", "test@163.com", "password", "usr@163.com", "title", "body");
}
2.6.16 Dial¶
Dial(Address, Timeout)
Get Original Socket access, support tcp, udp, tls, unix protocol.
Parameter value: Address is string type, fill in the address, TimeOut is the timeout
A JavaScript example:
function main(){
var client = Dial("tls://www.baidu.com:443"); // Dial supports tcp://, udp://, tls://, unix:// protocol, extra parameter to specify the number of seconds to timeout
if (client) {
client.write("GET / HTTP/1.1\nConnection: Closed\n\n"); // Write can be followed by a number parameter to specify the timeout, write to return the number of bytes successfully sent
while (true) {
var buf = client.read();// Read can be followed by a number parameter to specify a timeout, return null to indicate an error or timeout, or the socket is already closed
if (!buf) {
break;
}
Log(buf);
}
client.close();
}
}
Support websocket.
A JavaScript example of connecting to binance websocket ticker.
function main() {
LogStatus("connecting...");
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
if (!client) {
Log("Connection failed, program exited");
return
}
Log("The connection is successful and will automatically reconnected")
while (true) {
var buf = client.read() // Read only returns data obtained after calling read
if (!buf) {
break;
}
var table = {
type: 'table',
title: 'Quotes chart',
cols: ['Currency', 'highest', 'lowest', 'buy one', 'sell one', ' Last traded price', 'volume', 'Update time'],
rows: [],
};
var obj = JSON.parse(buf);
_.each(obj, function(ticker) {
table.rows.push([ticker.s, ticker.h, ticker.l, ticker.b, ticker.a, ticker.c, ticker.q, _D(ticker.E)])
});
LogStatus('`' + JSON.stringify(table) + '`')
}
client.close();
}
Here is another JavaScript example of connecting to OKEX websocket ticker. In this case, the bot needs to send a ping message every 30 seconds, and okex will send a pong back.
function main(){
var ws = Dial("wss://real.okex.com:10441/websocket")
if(ws){
ws.write("{'event':'addChannel','channel':'ok_sub_spot_btc_usdt_ticker'}")
var lastPingTime = new Date().getTime()
while(1){
var nowTime = new Date().getTime()
var ret = ws.read(10000) //timeout is 10000ms
Log("ret:", ret)
if(nowTime - lastPingTime > 15000){
var retPing = ws.write("{'event':'ping'}")
lastPingTime = nowTime
}
LogStatus("Now time", _D())
Sleep(1000)
}
}
}
2.6.16 HttpQuery¶
HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader)
Web URL access, support PUT
, GET
, POST
, DELETE
,etc.
Parameter values: all are string types
Get the content of a Url. If the second parameter PostData is a string, submit it as POST. The second parameter PostData can be a custom method such as:
HttpQuery("http://www.abc.com", {method:'PUT', data:'parameter1=value1¶meter2=value2'});//PUT method
HttpQuery("http://www.abc.com", {method:'PUT', data:'parameter1=value1¶meter2=value2', timeout:1000});
Passing the cookie string requires a third parameter, but does not require POST. Please set the second parameter to null
When runing in the backtes, the function returns the fixed string Dummy Data because the URL cannot be simulated.
You can use this interface to send text messages or interact with other APIs
HttpQuery("http://www.google.com"); // Get
HttpQuery("http://www.google.com", "parameter1=value1¶meter2=value2"); // Post
HttpQuery("http://www.google.com", null, "a=10; b=20", "User-Agent: Mobile\nContent-Type: text/html", true);
Example Accessing BIANACE APIs that do not require signatures:
var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'));
Log(exchangeInfo);
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'));
Log(ticker);
Note
The HttpQuery
function only supports JavaScript, for Python, using the urlib2
or request
library to send http requests directly.
2.6.18 Hash¶
Hash(Algo, OutputAlgo, Data)
Support hash calculation for md5/sha256/sha512/sha1, only supports in the real maket.
Parameter values: all are string types
The second parameter can be set to raw/hex/base64, which means output encrypted original content/hex encoded/base64 encoded.
function main(){
Log(Hash("md5", "hex", "hello"));
Log(Hash("sha512", "base64", "hello"));
}
2.6.19 HMAC¶
HMAC(Algo, OutputAlgo, Data, Key)
HMAC encryption calculation of md5/sha256/sha512/sha1 is supported, only supported in the real market.
Parameter values: all are string types.
The second parameter can be set to raw/hex/base64, which means output encrypted original content/hex encoded/base64 encoded.
2.6.20 UnixNano¶
UnixNano()
Return the nanosecond timestamp. If you need to obtain the millisecond timestamp, you can use the following code:
var time = UnixNano() / 1000000;
Log(_N(time, 0));
2.6.21 Unix¶
Unix()
Returns the second-level timestamp, which is only supported in a strategy written in C++
.
uint64_t t = Unix();
Log(t);
2.6.21 _C¶
_C(function, args…)
Retry function
Will always call the specified function to return successfully (function returns null or false will retry), such as _C (exchange.GetTicker)
, the
default retry interval is 3 seconds, you can call _CDelay
function to control the retry interval, such as _CDelay (1000)
means change the _C
function retry interval to 1 second, suggesting
Support Function:
exchange.GetTicker()
exchange.GetDepth()
exchange.GetTrade()`
exchange.GetRecords()
exchange.GetAccount()
exchange.GetOrders()
exchange.GetOrder()
A JavaScript example:
function main(){
var ticker = _C(exchange.GetTicker);
var depth = _C(exchange.GetDepth);
Log(ticker);
Log(depth);
}
Note
_C()
can often be misused as _C(exchange.GetRecords(PERIOD_H1))
, should be _C(exchange.GetRecords,PERIOD_H1)
2.6.22 _G¶
Global dictionary that can be saved after restart robot.
The KV dict is permanently stored in the local file. Each robot has a separate database. After the restart or the escrow withdrawal, K must be a number or a string. It is case-insensitive and V can be any JSON serialized content.
A JavaScript example:
_G('initValue', 1000); // set value
var initValue = _G('initValue'); // get value
_G("initValue", null); // remove global variable "initValue"
_G(null); //Remove all global variables
_G(); // Returns the ID of the current robot
2.6.23 _D¶
_D(timestamp, fmt="yyyy-MM-dd hh:mm:ss")
Returns the specified timestamp
Returns the specified timestamp (ms) string, returns the current time without any parameter, such as _D(), or _D(1478570053241), The default format is yyyy-MM-dd hh:mm:ss.
function main(){
while(true){
var time = _D();
LogStatus('Last update time: ', time);
//do some thing
}
}
2.6.24 _N¶
_N(num, precision)
Format a float
Parameter value, num is number type, precision is integer number
For example _N (3.1415, 2)
will delete the value after the two decimal points, return “3.14”. _N(1321,-2)
will return “1300”.
2.6.25 _Cross¶
_Cross(arr1, arr2)
Returns the number of cross periods of the arrays arr1 and arr2.
A positive number is the upper pass period, a negative number indicates the period of the wear pass, and a 0 indicates the current price. Can be used in MACD strategy.
Parameter value: array of numbers
Specific instructions for use: built-in function _Cross analysis and instructions
var arr1 = [1,2,3,4,5,6,8,8,9]
var arr2 = [2,3,4,5,6,7,7,7,7]
function main(){
Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2))
Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1))
}
2.6.26 TA Indicator function¶
TA-Lib Indicator Library. support MACD
, EMA
, KDJ
, ATR
, RSI
, etc…
Need to add TA. or talib. prefix when calling indicator function.
For more details about TA-Lib functions, check on http://mrjbq7.github.io/ta-lib/
You can also install TA-lib library of Python by yourself.
JavaScript example:
function main(){
var records = exchange.GetRecords();
var macd = TA.MACD(records);
Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2]);
var atr = TA.ATR(records, 14);
// Print out the last row of values
Log(macd[0][records.length-1], macd[1][records.length-1],
macd[2][records.length-1]);
Log(atr[atr.length-1]);
Log(talib.MACD(records));
Log(talib.MACD(records, 12, 26, 9));
Log(talib.OBV(records));
// Talib can also pass in an array of numbers, which can be passed in successively
// Such as: OBV(Records[Close], Records[Volume]), need Close, Volume two array parameters
Log(talib.OBV([1,2,3], [7.1, 6.2, 3,3]));
// You can also directly pass in an array of records containing the Close, Volume property
Log(talib.OBV(records));
Log(TA.Highest(records, 30, 'High'));
Log(TA.Highest([1,2,3,4], 0));
// For Python, the system extends the properties of the array returned by GetRecords, adding Open, High, Low, Close, Volume, to facilitate talib calls, such as
talib.MACD(records.Close);
/*For Python, the system expands the properties of the array returned by GetRecords, adds Open, High, Low, Close, Volume,
and facilitates talib calls. For example, the Close property returns the Close property of all records members as a numpy array passed to talib.
The same as other properties*/
}
2.6.27 Chart¶
Chart({…})
Will draw a figure in you robot management page.
Chart is based on HighStocks. check on http://api.highcharts.com/highstock for more details.
The parameter is a HighCharts.StockChart parameter that can be JSON-serialized and has a __isStock
attribute that is not exist in the original one.
If __isStock
is false
, chart will displayed as an ordinary chart.
The return object can call add([series index(like 0), data])
to add data to the specified index series,
call reset()
to clear the chart data, reset can take a number parameter, specify the number of reservations.
You can call add([series index, data, index of data in the series])
to change the data,
Can be negative, -1 refers to the last, -2 is the second to last, such as:
Chart.add([0, 13.5, -1])
, change the data of the first-to-last point of series[0].data.
Supports the display of multiple charts. You only need to pass in array parameters like: var chart = Chart([{...}, {...}, {...}])
.
A JavaScript example of using Chart to draw the prices of two coins.two exchanges need to be added before run the robot.
// This chart is an object in the JS language. Before using the Chart function, we need to declare an object variable chart that configures the chart.
var chart = {
// Whether the mark is a general chart, if you are interested, you can change it to false and run it.
__isStock: true,
tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'}, // Zoom tool
title : { text : 'Spread Analysis Chart'}, // title
rangeSelector: { // Selection range
buttons: [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
selected: 0,
inputEnabled: false
},
xAxis: { type: 'datetime'}, // The horizontal axis of the coordinate axis is the x axis and the current setting type is :time
yAxis : { // The vertical axis of the axis is the y axis, and the default value is adjusted with the data size.
title: {text: 'Spread'}, // title
opposite: false, // Whether to enable the right vertical axis
},
series : [ // Data series, this attribute is saved for each data series (line, K-line graph, label, etc...)
{name : "line1", id : "Line 1,buy1Price", data : []}, // The index is 0, the data array is stored in the index series of data
{name : "line2", id : "Line 2,lastPrice", dashStyle : 'shortdash', data : []},
// The index is 1, dashStyle is set: 'shortdash' ie: Set the dotted line.
]
};
function main(){
var ObjChart = Chart(chart); // Call the Chart function to initialize the chart.
ObjChart.reset(); // Empty the chart
while(true){
var nowTime = new Date().getTime(); // Get the timestamp of this poll, which is a millisecond timestamp. Used to determine the position of the X axis written to the chart.
var tickerOne = _C(exchanges[0].GetTicker); // Get market data
var tickerTwo = _C(exchanges[1].GetTicker);
ObjChart.add([0, [nowTime, tickerOne.Last]]); // Use the timestamp as the X value and buy the price as the Y value to pass the index 0 data sequence.
ObjChart.add([1, [nowTime, tickerTwo.Last]]); // Same as above
ObjChart.update(chart); // Update the chart to show it.
Sleep(2000);
}
}
3.1 Use Websocket¶
For JavaScript:
function main() {
LogStatus("connecting...");
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
if (!client) {
Log("Connection failed, program exited");
return
}
Log("The connection is successful and the disconnected line is automatically reconnected")
while (true) {
var buf = client.read() // Read only returns data obtained after calling read
if (!buf) {
break;
}
var table = {
type: 'table',
title: 'Quotes chart',
cols: ['Currency', 'highest', 'lowest', 'Bid', 'Ask', ' Last traded price', 'volume', 'Update time'],
rows: [],
};
var obj = JSON.parse(buf);
_.each(obj, function(ticker) {
table.rows.push([ticker.s, ticker.h, ticker.l, ticker.b, ticker.a, ticker.c, ticker.q, _D(ticker.E)])
});
LogStatus('`' + JSON.stringify(table) + '`')
}
client.close();
}
For Python, you can use Dial()
function as well, or websocket_client
library to access websocket.
3.2 Use C++¶
There are some difference between C++ and JavaScript in writing strategy.
void main() {
if (!Test("c++")) {
Panic("please download the lastest docker");
}
// json: https://github.com/nlohmann/json
// using Valid to judge return object is null or not.
LogProfitReset();
LogReset();
Log(_N(9.12345, 2));
Log("use _C", _C(exchange.GetTicker), _C(exchange.GetAccount));
// test async
auto routineTicker = exchange.Go("GetTicker");
auto routineDepth = exchange.Go("GetDepth");
Ticker asyncTicker;
Depth asyncDepth;
// No timeout, wait until Ticker is returned
if (routineTicker.wait(asyncTicker)) {
Log("Wait Ticker OK", asyncTicker.Valid, asyncTicker, asyncTicker.Last);
} else {
Log("Wait Ticker fail");
}
// With 300ms tiemout, 0 means return immediately.
if (routineDepth.wait(asyncDepth, 200)) {
// not sure the depth returned is valid, use asyncDepth.Valid.
Log("Wait Depth OK", asyncDepth.Valid, asyncDepth);
} else {
Log("Wait Depth timeout");
}
auto records = _C(exchange.GetRecords);
Log("Last Kline", records[records.size()-1].Time, _D(records[records.size()-1].Time), records[records.size()-1]);
// Test TA
auto ema = TA.EMA(records, 20);
Log("EMA", ema[ema.size()-1], ema[ema.size()-2], ema[ema.size()-3]);
auto macd = talib.MACD(records);
Log("MACD", macd[0][macd[0].size()-1], macd[1][macd[1].size()-1], macd[2][macd[2].size()-1]);
//SetErrorFilter("timeout");
Log(GetOS(), GetPid(), GetLastError(), "MD5", MD5("hello"));
Log("Hash", Hash("md5", "hex", "hello"), Hash("sha512", "base64", "hello"));
Log("HMAC", HMAC("sha512", "base64", "hello", "pass"));
Log(Version(), Unix(), UnixNano());
Log("Start Test Chart");
Chart c = Chart(R"EOF({"chart":{"type":"line"},"title":{"text":"Simple Chart"},"xAxis":{"title":{"text":"Date"}},"yAxis":{"title":{"text":"Number"}},"series":[{"name":"number","data":[]}]})EOF");
c.reset();
for (size_t i = 0; i < 10; i++) {
c.add(0, {(Unix() + i)*1000, rand() % 100});
}
Log(exchange.GetName(), exchange.GetLabel(), exchanges.size());
auto acc = exchange.GetAccount();
if (acc.Valid) {
Log(acc);
}
// Using LogStatus and json draw a table, learn more about json libray: https://github.com/nlohmann/json
json tbl = R"({"type" : "table", "title" : "AAA", "cols" : ["Head1", "Head2"], "rows": []})"_json;
tbl["rows"].push_back({"111", "222"});
tbl["rows"].push_back({"col2", "col22"});
LogStatus("`"+tbl.dump()+"`");
auto ticker = exchange.GetTicker();
if (ticker.Valid) {
Log(ticker);
Log(ticker.Info); // Info Struct is json object
}
auto d = exchange.GetDepth();
if (d.Valid) {
Log(d.Asks[0], d.Bids[0]);
}
// Test features
if (exchange.GetName() == "Futures_OKCoin") {
exchange.SetContractType("this_week");
exchange.SetMarginLevel(20);
exchange.SetDirection("closebuy");
auto positions = exchange.GetPosition();
if (positions.Valid) {
Log(positions);
}
}
// test other function
Log("HttpQuery", HttpQuery("http://www.baidu.com/404").size());
auto obj = json::parse(HttpQuery("http://www.baidu.com/404", "", "", "", true));
string body = obj["Body"];
Log("HttpQuery", body.size(), obj["Header"].dump());
Log(Mail("smtp://smtp.163.com", "test@163.com", "password", "admin@163.com", "title", "test c++ email"));
// Test Dial
auto client = Dial("tcp://www.baidu.com:80");
if (client.Valid) {
client.write("GET / HTTP/1.1\nHost: www.baidu.com\nConnection: Close\n\n");
while (true) {
string buf = client.read();
if (buf == "") {
break;
}
Log("Dial receive", buf.size());
}
client.close();
}
_G("OK","xxx");
Log(_G("OK"));
_G("OK","yyyyyy");
Log(_G("OK"));
_G("OK",NULL);
Log(_G("OK"));
}
3.3 Sell ALL AltCoin to BTC in Binance¶
This strategy will sell all your AltCoin to BTC (or ETH, BNB, USDT), learn how to trade multiple trading pair, and follow the price and amount filter of exchange.
function main() {
var quoteCurrency = 'BTC'; //Can be 'ETH', 'BNB', 'USDT'
Log("Quote Currency", quoteCurrency);
var symbols = JSON.parse(_C(HttpQuery, "https://api.binance.com/api/v1/exchangeInfo")).symbols;
_.each(_C(exchange.GetAccount).Info.balances, function(ele) {
if (ele.asset == quoteCurrency) {
return
}
var totalV = parseFloat(ele.free) + parseFloat(ele.locked);
if (totalV == 0) {
return;
}
var cfg = _.findWhere(symbols, {symbol: ele.asset+quoteCurrency});
if (!cfg) {
Log("Not found", ele.asset, "trading pair", ele);
return;
}
var filter = _.findWhere(cfg.filters, {filterType: "LOT_SIZE"});
if (!filter) {
return;
}
var v = _N(parseInt(totalV/filter.stepSize)*filter.stepSize, cfg.baseAssetPrecision);
if (v > 0) {
Log(ele, "stepSize", filter.stepSize);
exchange.IO("currency", ele.asset + "_"+quoteCurrency);
while (true) {
var orders = _C(exchange.GetOrders);
_.each(orders, function(order) {
exchange.CancelOrder(order.Id);
});
if (orders.length == 0) {
break;
}
}
exchange.Sell(-1, v);
Log(ele);
}
});
Log("Done, Now", quoteCurrency, "Balance", _C(exchange.GetAccount).Balance);
}
3.4 Moving Average Strategy¶
The moving average (MA) is a simple technical analysis tool that smooths out price data by creating a constantly updated average price.
Check on https://www.fmz.com/strategy/103070 for parameters configs.The global variables FastPeriod
, SlowPeriod
,etc… are defined in configs.
Source code:
function main() {
var initAccount = _C(exchange.GetAccount);//using _C() to retry
var ticker = exchange.GetTicker();
//calc InitValue to log profit
var InitValue = (initAccount.Stocks + initAccount.FrozenStocks)*ticker.Last \
+ initAccount.Balance + initAccount.FrozenBalance;
while (true) {
var records = _C(exchange.GetRecords);
ticker =_C(exchange.GetTicker);
var FastRecords = TA.MA(records,FastPeriod);// using MA of TA-Lib
var SlowRecords = TA.MA(records,SlowPeriod);
var NowAccount = _C(exchange.GetAccount);
var n = _Cross(FastRecords, SlowRecords);// using _Cross(), check on global function
if (n >= EnterPeriod && NowAccount.Balance > 0) {
var Price = _N(ticker.Sell+Slippage, 2); // add Slippage to make sure order can be done
var Amount = _N(0.99*NowAccount.Balance/Price, 3);
if(Amount>0.1){
var id = exchange.Buy(Price, Amount);
//Cancel the pending order
if(exchange.GetOrders(id).Status == ORDER_STATE_PENDING){exchange.CancelOrder(id);}
LogProfit((NowAccount.Stocks + NowAccount.FrozenStocks)*ticker.Last\
+ NowAccount.Balance + NowAccount.FrozenBalance - InitValue);
}
}
if(n <= -EnterPeriod && NowAccount.Stocks > 0) {
var Price = _N(ticker.Buy-Slippage, 2);
var Amount = _N(NowAccount.Stocks, 3);
if(Amount>0.1){
var id = exchange.Sell(Price, Amount);
if(exchange.GetOrders(id).Status == ORDER_STATE_PENDING){exchange.CancelOrder(id);}
LogProfit((NowAccount.Stocks + NowAccount.FrozenStocks)*ticker.Last\
+ NowAccount.Balance + NowAccount.FrozenBalance - InitValue);
}
}
Sleep(Interval*1000);
}
}
3.5 Iceberg Buy Order¶
Check on https://www.fmz.com/strategy/103319.
Source code:
var floatAmountBuy = 20
var floatAmountSell = 20
var diffPrice = 3
var Interval = 3000
function CancelPendingOrders() {
var orders = _C(exchange.GetOrders);
for (var j = 0; j < orders.length; j++) {
exchange.CancelOrder(orders[j].Id, orders[j])
}
}
function GetPrice(depth) {
var price = {buy:0, sell:0}
var askAmount = 0
var bidAmount = 0
for(var i=0; i<depth.Bids.length; i++){
askAmount += depth.Asks[i].Amount
bidAmount += depth.Bids[i].Amount
if(askAmount >= floatAmountBuy && !price.buy){
price.buy = depth.Asks[i].Price
}
if(bidAmount >= floatAmountSell && !price.sell){
price.sell = depth.Bids[i].Price
}
}
if(!price.buy || !price.sell){
price = {buy:depth.Asks[depth.Asks.length-1].Price, sell:depth.Bids[depth.Bids.length-1].Price}
}
return price
}
function onTick() {
var price = GetPrice(_C(exchange.GetDepth))
var buyPrice = price.buy + 0.01
var sellPrice = price.sell - 0.01
if ((sellPrice - buyPrice) <= diffPrice){
buyPrice -= 10
sellPrice += 10
}
CancelPendingOrders()
var account = _C(exchange.GetAccount)
var amountBuy = _N((account.Balance / buyPrice-0.01), 2)
var amountSell = _N((account.Stocks), 2)
if (amountSell > 0.02) {
exchange.Sell(sellPrice, amountSell)
}
if (amountBuy > 0.02) {
exchange.Buy(buyPrice, amountBuy)
}
}
function main() {
while (true) {
onTick()
Sleep(Interval)
}
}
3.6 Dual Thrust OKEX Feature¶
A classic breakout strategy, Check on https://www.fmz.com/strategy/103247 for configs.
You can learn how to trade features and draw charts from the source code.
learn more on https://www.quantconnect.com/tutorials/strategy-library/dual-thrust-trading-algorithm
Source code:
var ChartCfg = {
__isStock: true,
title: {
text: 'Dual Thrust Up-Down Track'
},
yAxis: {
plotLines: [{value: 0,
color: 'red',
width: 2,
label: {
text: 'Up Track',
align: 'center'}
},
{value: 0,
color: 'green',
width: 2,
label: {
text: 'Down Track',
align: 'center'},
}
]
},
series: [{type: 'candlestick',
name: 'current cycle',
id: 'primary',
data: []
},
{type: 'flags',
onSeries: 'primary',
data: [],
}
]
};
var STATE_IDLE = 0;
var STATE_LONG = 1;
var STATE_SHORT = 2;
var State = STATE_IDLE;
var LastBarTime = 0;
var UpTrack = 0;
var BottomTrack = 0;
var chart = null;
var InitAccount = null;
var LastAccount = null;
var Counter = {
w: 0,
l: 0
};
function GetPosition(posType) {
var positions = exchange.GetPosition();
for (var i = 0; i < positions.length; i++) {
if (positions[i].Type === posType) {
return [positions[i].Price, positions[i].Amount];
}
}
return [0, 0];
}
function CancelPendingOrders() {
while (true) {
var orders = exchange.GetOrders();
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
Sleep(Interval);
}
if (orders.length === 0) {
break;
}
}
}
function Trade(currentState, nextState) {
var pfn = nextState === STATE_LONG ? exchange.Buy : exchange.Sell;
if (currentState !== STATE_IDLE) {
exchange.SetDirection(currentState === STATE_LONG ? "closebuy" : "closesell");
while (true) {
var amount = GetPosition(currentState === STATE_LONG ? PD_LONG : PD_SHORT)[1];
if (amount === 0) {
break;
}
// pfn(amount);
pfn(nextState === STATE_LONG ? _C(exchange.GetTicker).Sell * 1.001 : _C(exchange.GetTicker).Buy * 0.999, amount);
Sleep(Interval);
CancelPendingOrders();
}
var account = exchange.GetAccount();
if (account.Stocks > LastAccount.Stocks) {
Counter.w++;
} else {
Counter.l++;
}
LogProfit(_N(account.Stocks - InitAccount.Stocks), "Profit rate:", _N((account.Stocks - InitAccount.Stocks) * 100 / InitAccount.Stocks) + '%');
LastAccount = account;
}
exchange.SetDirection(nextState === STATE_LONG ? "buy" : "sell");
while (true) {
var pos = GetPosition(nextState === STATE_LONG ? PD_LONG : PD_SHORT);
if (pos[1] >= AmountOP) {
Log("Average Price", pos[0], "amount:", pos[1]);
break;
}
// pfn(AmountOP-pos[1]);
pfn(nextState === STATE_LONG ? _C(exchange.GetTicker).Sell * 1.001 : _C(exchange.GetTicker).Buy * 0.999, AmountOP-pos[1]);
Sleep(Interval);
CancelPendingOrders();
}
}
function onTick(exchange) {
var records = exchange.GetRecords();
if (!records || records.length <= NPeriod) {
return;
}
var Bar = records[records.length - 1];
if (LastBarTime !== Bar.Time) {
var HH = TA.Highest(records, NPeriod, 'High');
var HC = TA.Highest(records, NPeriod, 'Close');
var LL = TA.Lowest(records, NPeriod, 'Low');
var LC = TA.Lowest(records, NPeriod, 'Close');
var Range = Math.max(HH - LC, HC - LL);
UpTrack = _N(Bar.Open + (Ks * Range));
DownTrack = _N(Bar.Open - (Kx * Range));
if (LastBarTime > 0) {
var PreBar = records[records.length - 2];
chart.add(0, [PreBar.Time, PreBar.Open, PreBar.High, PreBar.Low, PreBar.Close], -1);
} else {
for (var i = Math.min(records.length, NPeriod * 3); i > 1; i--) {
var b = records[records.length - i];
chart.add(0, [b.Time, b.Open, b.High, b.Low, b.Close]);
}
}
chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close]);
ChartCfg.yAxis.plotLines[0].value = UpTrack;
ChartCfg.yAxis.plotLines[1].value = DownTrack;
ChartCfg.subtitle = {
text: 'Up Track: ' + UpTrack + ' Down Track: ' + DownTrack
};
chart.update(ChartCfg);
chart.reset(PeriodShow);
LastBarTime = Bar.Time;
} else {
chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close], -1);
}
LogStatus("Price:", Bar.Close, "Up:", UpTrack, "Down:", DownTrack, "Wins: ", Counter.w, "Losses:", Counter.l, "Date:", new Date());
var msg;
if (State === STATE_IDLE || State === STATE_SHORT) {
if (Bar.Close >= UpTrack) {
msg = 'Long Price: ' + Bar.Close + ' Up Track:' + UpTrack;
Log(msg);
Trade(State, STATE_LONG);
State = STATE_LONG;
chart.add(1, {x:Bar.Time, color: 'red', shape: 'flag', title: 'Long', text: msg});
}
}
if (State === STATE_IDLE || State === STATE_LONG) {
if (Bar.Close <= DownTrack) {
msg = 'Short Price: ' + Bar.Close + ' Down Track:' + DownTrack;
Log(msg);
Trade(State, STATE_SHORT);
chart.add(1, {x:Bar.Time, color: 'green', shape: 'circlepin', title: 'Short', text: msg});
State = STATE_SHORT;
}
}
}
function onexit() {
var pos = exchange.GetPosition();
if (pos.length > 0) {
Log("Warning, has positions when exiting", pos);
}
}
function main() {
if (exchange.GetName() !== 'Futures_OKCoin') {
throw "Only support OKEX features";
}
exchange.SetRate(1);
exchange.SetContractType(["this_week", "next_week", "quarter"][ContractTypeIdx]);
exchange.SetMarginLevel([10, 20][MarginLevelIdx]);
if (exchange.GetPosition().length > 0) {
throw "Can't have Positions when start.";}
CancelPendingOrders();
InitAccount = LastAccount = exchange.GetAccount();
LoopInterval = Math.min(1, LoopInterval);
Log('Exchange Name:', exchange.GetName(), InitAccount);
LogStatus("Ready...");
LogProfitReset();
chart = Chart(ChartCfg);
chart.reset();
LoopInterval = Math.max(LoopInterval, 1);
while (true) {
onTick(exchange);
Sleep(LoopInterval * 1000);
}
}
3.7 High Frequency Marketmaker¶
This is a simple but powerful strategy that used to earn thousands of times in real BTC spot markets. Can’t run it on exchanges that have high trade fee.
Source code:
var floatAmountBuy = 20;
var floatAmountSell = 20;
var diffPrice = 3;
var Interval = 3000;
function CancelPendingOrders() {
var orders = _C(exchange.GetOrders);
for (var j = 0; j < orders.length; j++) {
exchange.CancelOrder(orders[j].Id, orders[j]);}
}
function GetPrice(Type, depth) {
var amountBids = 0;
var amountAsks = 0;
if(Type == "Buy"){
for(var i=0;i<depth.Bids.length;i++){
amountBids += depth.Bids[i].Amount;
if (amountBids > floatAmountBuy){
return depth.Bids[i].Price + 0.01;
}
}
}
if(Type == "Sell"){
for(var j=0; j<depth.Asks.length; j++){
amountAsks += depth.Asks[j].Amount;
if (amountAsks > floatAmountSell){
return depth.Asks[j].Price - 0.01;
}
}
}
return depth.Asks[0].Price
}
function onTick() {
var depth = _C(exchange.GetDepth);
var buyPrice = GetPrice("Buy", depth);
var sellPrice = GetPrice("Sell", depth);
if ((sellPrice - buyPrice) <= diffPrice){
buyPrice -= 10;
sellPrice += 10;
}
CancelPendingOrders();
var account = _C(exchange.GetAccount);
var amountBuy = _N((account.Balance / buyPrice-0.01), 2);
var amountSell = _N((account.Stocks), 2);
if (amountSell > 0.02) {
exchange.Sell(sellPrice, amountSell);
}
if (amountBuy > 0.02) {
exchange.Buy(buyPrice, amountBuy);
}
}
function main() {
while (true) {
onTick();
Sleep(Interval);
}
}