Elementary Tutorial for FMZ Quant platform Strategy Writing

Author: Ninabadass, Created: 2022-03-18 09:00:46, Updated: 2022-04-02 11:48:15

you can use Python to write directly to the database.

function onexit(){
    _G('profit', profit)
}
function main(){
    _G("num", 1); // Set a global variable num, with a value of 1 second 
    _G("num", "ok"); // Change a global variable num, whose value is the string "ok"
    _G("num", null); // Delete the global variable num 
    _G("num"); // Return the value of the global variable num; if it does not exist, return null

    var profit = 0
    if(_G('profit')){
        profit = _G('profit')
    }
}

_N

When placing an order, the precisions of price and volume normally need to be controlled; FMZ has builted in the _N function to determine the decimal places to be saved; for example, the result of _N(4.253,2) is 4.25.

_C

Calling the plaform API cannot guarantee the access is successful every time, and _C is an automatic retry function. It will always call the specified functions until it returns successfully (the function will retry if it returns null or false); for example, _C(exchange.GetTicker), with the default retry interval of 3 seconds, and you can call _CDelay function to control the retry interval, such as _CDelay(1000), which means to change the _C function retry interval to 1 second. It is recommended to use _C to operate fault tolerance in GetTicker(), exchange.GetDepth, GetTrade, GetRecords, GetAccount, GetOrders and GetOrder to prevent the program interruption caused by the access failure.

CancelOrder cannot use the _C function, because there are various reasons for the failure to cancel an order. If an order has been executed, then canceling the order will return a failure, and using the _C function will result in retrying all the time. The _C function can also pass in parameters and is also used in custom functions.

function main(){
    var ticker = _C(exchange.GetTicker)
    var depth = _C(exchange.GetDepth)
    var records = _C(exchange.GetRecords, PERIOD_D1) // Pass in the parameters
}

_D

Calling _D() directly will return the current time string, such as: 2019-08-15 03:46:14. If it is called during the backtest, the backtest time will be returned. You can use the _D function to judge the time, such as: _D().slice(11) > '09:00:00':. _D(timestamp, fmt), will convert the ms timestamp to a time string, such as _D(1565855310002). The fmt parameter is the time format, and the default is yyyy-MM-dd hh:mm:ss.

TA Indicator Functions

For some commonly used indicator functions, such as MA\MACD\KDJ\BOLL and other common indicators, which have been directly built in by FMZ platform, and the specific supported indicators can be found in the API document.

Before using the indicator functions, it is best to judge the length of K-line. When the previous K-line length cannot meet the required period for calculation, the result is null. For example, if the input K-line length is 100 and the period for calculating MA is 10, then the first 9 values are all null, and the calculation after the formar 9 values will be done normally.

JavaScript also supports the complete talib, as a third-party library, with invocation method such as talib.CCI(records). Please refer to http://ta-lib.org/function.html. For Python, you can install the talib library by yourself. Due to the need for compilation, you cannot simply use pip to install. You can search for the installation method by yourself.

Indicator functions can not only pass the K-line data, but also pass any array

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    if (records && records.length > 9) {
        var ma = TA.MA(records, 14)
        Log(ma)
    }
}

Commonly Used Functions in JavaScript

Here we introdue some commonly used JavaScript functions in the bots.

  • Date.now() returns the current timestamp;
  • parseFloat() transfers strings into numbers, such as parseFloat("123.21");
  • parseInt() transfers strings into integers;
  • num.toString() transfers numbers into strings, with number variable num;
  • JSON.parse() formats Json strings, such as JSON.parse(exchange.GetRawJSON());
  • JavaScript has its own Math functions, such as the common math operations, inluding Math.max(), Math.abs() and so on; reference: https://www.w3school.com.cn/jsref/jsref_obj_math.asp ;
  • The third-party math library used by FMZ; reference: https://mathjs.org/ ;
  • The third-party underscore library of JavaScript used by FMZ, which is recommended to have a knowledge of and which makes the tedious Js operations more convenient; reference: https://underscorejs.org/.

Template

There are many situations that need to be considered when writing a bot strategy function. For example, a simple function such as buying 5 coins, we need to consider: Is the current balance enough? How much is the order price? What is the precision? Do you need to split orders to avoid impacting the market? How to deal with unfinished orders? And some details like that. In different strategies, these functions are the same, so you can make them into a template. Following the official templates, users can also write their own template strategies. Here we will introduce several very commonly used template class libraries officially released by FMZ, so that users can quickly write their own strategies.

The JavaScript cryptocurrency trading library and commodity futures trading library are built in by default and do not need to be copied. Other template libraries can be found at the strategy “Square” (https://www.fmz.com/square/20/1). Copy and save the template library, and check the library to be used when creating your own strategy.

JavaScript template functions all start with $, while Python ones all start with ext.

Cryptocurrency Trading library

Source Code Address: https://www.fmz.com/strategy/10989, which has already been built-in, so no need to copy. Specific funtion implementation can directly refer to the source code.

Get Account:

$.GetAccount(e)

Log($.GetAccount()); // Obtain the account information, with fault tolerance function 
Log($.GetAcccount(exchanges[1]));

Order Placing & Canceling:

$.Buy/Sell(e, amount)
$.Buy(0.3); // The main platform buys 0.3 coin
$.Sell(0.2); // The main platform sells 0.2 coin
$.Sell(exchanges[1], 0.1); // The secondary platform sells 0.1 coin
$.CancelPendingOrders(e, orderType)

$.CancelPendingOrders(); // Cancel all entrusted orders of the main platform 
$.CancelPendingOrders(ORDER_TYPE_BUY); // Cancel all buy orders of the main platform
$.CancelPendingOrders(exchanges[1]); // Cancel all orders of the secondary platform
$.CancelPendingOrders(exchanges[1], ORDER_TYPE_SELL); // Cancel all sell orders of the secondary platforom 

Judge the Cross:

$.Cross(periodA, periodB) / $.Cross(arr1, arr2);

var n = $.Cross(15, 30);
var m = $.Cross([1,2,3,2.8,3.5], [3,1.9,2,5,0.6])
If n = 0, it means that the current prices of exactly 15-period EMA and 30-period EMA are equal. 
If n > 0, such as 5, it means that the 15-period EMA up-crosses the 30-period EMA by 5 periods (Bar)
If n < 0, such as -12, it means that the 15-period EMA down-crosses the 30-period EMA by 12 periods (Bar)
If it is not an array passed to the Cross, the function automatically obtains the K-line for moving average calculation.
If an array is passed to Cross, compare directly.

$.withdraw(e, currency, address, amount, fee, password) function:

$.withdraw(exchange, "btc", "0x.........", 1.0, 0.0001, "***")

Commodity Futures Trading library

For the use of the commodity futures trading library is very stable, it is recommended. Source code address: https://www.fmz.com/strategy/12961, which has already been built-in, so no need to copy. Specific funtion implementation can directly refer to the source code.

CTA Library

  • The bot will automatically map the index to the main continuous contract;
  • it Will automatically handle the move;
  • you can specify the mapping for backtest, such as rb000/rb888, which is to map the k-line of rb index to trade the main continuous contract;
  • it can also be mapped to other contracts; for example, rb000/MA888 is to look at the K-line of the rb index to trade the MA main continuous contract.
function main() {
    $.CTA("rb000,M000", function(r, mp) {
        if (r.length < 20) {
            return
        }
        var emaSlow = TA.EMA(r, 20)
        var emaFast = TA.EMA(r, 5)
        var cross = $.Cross(emaFast, emaSlow);
        if (mp <= 0 && cross > 2) {
            Log("Golden cross period", cross, "the moment position", mp);
            return 1
        } else if (mp >= 0 && cross < -2) {
            Log("Death cross period", cross, "the moment position", mp);
            return -1
        }
    });
}

Invocation Example of library

function main() {
    var p = $.NewPositionManager();
    p.OpenShort("MA609", 1);
    p.OpenShort("MA701", 1);
    Log(p.GetPosition("MA609", PD_SHORT));
    Log(p.GetAccount());
    Log(p.Account());
    Sleep(60000 * 10);
    p.CoverAll("MA609");
    LogProfit(p.Profit());
    Log($.IsTrading("MA609"));
    // Multiple varieties use the trading queue to complete the non-blocking trading task
    var q = $.NewTaskQueue();
    q.pushTask(exchange, "MA701", "buy", 3, function(task, ret) {
        Log(task.desc, ret)
    })
    while (true) {
        // Call "poll" to execute the unfinished tasks in the spare time
        q.poll()
        Sleep(1000)
    }
}

Drawing Library

For the raw functions for drawing are very complicated, which will be introduced in the next tutorial, we recommend beginners to use the drawing library, to draw very simple line charts and k-line charts, etc. The simple drawing library has been built in FMZ, which can be seen on the strategy editing page; if the library is not built in yet, users need to copy and save, to check and use the library in the strategy.

img

Copy address of Javascript version drawing library: https://www.fmz.com/strategy/27293 Copy address of Python version drawing library: https://www.fmz.com/strategy/39066

Specific example:

function main() {
    while (true) {
        var ticker = exchange.GetTicker()
        if (ticker) {
            $.PlotLine('Last', ticker.Last) // You can draw two lines at the samw time, "Last" is the name of the line
            $.PlotLine('Buy', ticker.Buy)
        }
        Sleep(6000)
    }
}

Strategy Parameter Settings

Under the “Edit Strategy”, there are strategy parameter settings, which are equal to the global variables of the strategy, and can be accessed at any location in the code. The strategy parameters can be modified on the bot page, and they will be valid after restart. Therefore, some variables can be set to the parameters, and the parameters can be modified without modifying the strategy.
img

  • Varable Name: namely the number, string and combox etc. in the above image,which can be directly used in the strategy group.
  • Description: the name of a parameters on strategy interface, more convenient for users to understand the meaning of the parameter.
  • Remark: the detailed explanation of a parameter, which will be displayed accordingly when the mouse is over the parameter.
  • Type: the type of a parameter, which will be introduced in details later.
  • Default: the default of the a parameter.

It is very easy to undertand string type and number type. which are very commonly used types. The combo box will display the options in the box on the parameter interface. For example, you can set the SYMBOL paramater as BTC|USDT|ETH in the combo box; if you choose USDT in the box on the page, the SYMBOL value in the strategy is USDT index 1. Check options refers to an optional checkbox; check means true, while no check means false.

There are more parameters for settings; referene:https://www.fmz.com/api.

Strategy Backtest

When the quantization of a strategy is finished, you can test it by the history data, to check out the profit situation of the strategy in the history date. Of course, the backtest result is only for reference. FMZ Quant platform supports the backtests of cryptocurrency spot and futures, BitMEX perpetual contract, commodity futures, in which only mainstream cryptocurrencies are supported. The Javascript backtest is run on the browser; the Python backtest is on the docker, and our platform provides public dockers for users. The backtest of Mylanguage has more parameters for settings, and more details can be referred in the document of Mylanguage.

Baktest Mechanism

Onbar backtest mechanism is based on K-line, that is, each K-line will generate one point in time for backtest. On the point in time, you can obtain the information including the open, close, highest and lowest prices and trading volume of the current K-line, as well as the history K-line information before the point. The shortcoming of this kind of mechanism is very obvious: only one purchase can be generated on one K-line; usually the referred price is the close price of thr K-line. also, one K-line can only obtain four prices, namely the close, open, highest and lowest prices; the information, icluding how the prices change in one K-line and whether the highest price or the lowest price changes first, cannot be obtained. Take the one-hour K-line as an example. The market quote information is surely obtained every several seconds in the bot, and trading commands will be conducted in the bot not after the K-line is finished. The advantage of onbar backtest mechanism is easy to understand, and fast to backtest.

The backtest on FMZ contains two kinds, namely the simulation level backtest and the real market level backtest. The simulation level backtest can generate the simulated tick according to the underlayer K-line periods, and each underlayer K-line period will generate 14 backtest time points. However, the real market level backtest will actually collect tick, every several seconds, and now it supports real depth (inluding 20 levels), and real execution trade by tarde. The date volume is pretty huge, and the backtest speed is very slow, so the backtest cannot be run in a long time. FMZ backtest mechanism can realize multiple trades of the startegy on one K-line, to prevent the situation that the trading can only be executed by the close price, and also increasingly targeting at and taking care of the backtest speed. For more detailed instructions: https://www.fmz.com/bbs-topic/9126.

The framework of backtest and bot are the same, both an infinite loop. Because the backtest is to skip to different backtest points, the backtest can be run without using “Sleep”, and it will automatically skip to the next time point when one loop is over. However, Python, due to the program mechanism, needs a constraint of Sleep(10), to avoid being stuck.

Backtest Matching

The backtest engine will match the order price placed by the user and the market price at the backtest time point. If the buy price is higher than sell one, the sell one will be executed. If the trading cannot be executed, a pending order will be generated. Slippage needs to be added to ensure the trading. If the position cannot be opened or closed during the backtest, check whether the position is frozen due to unfinished orders.

Backtest Page Settings

img

  • 1.choosing the page of “Backtest”, on the left of which is “Edit Strategy” page;
  • 2.the starting time and the ending time of the backtest; for the data might be incomplete, the backtest may directly start from the time when the data exists;
  • 3.the default period of backtesting the GetRecords() function; you can also specify a period parameter in the code;
  • 4.choosing the backtest mechanism;
  • 5.displaying or hiding more backtest settings;
  • 6.the maximums of log items, profit log items and chart log items, to prevent the browser from the breakdown caused by huge data amount;
  • 7.the period generated by the underlayer tick according to K-line;
  • 8.traing slippoint;
  • 9.fault tolerance, which will simulate the situation when the API request is wrong, and test the fault tolerance capacity of the strategy;
  • 10.whether to draw the market chart; if a TA indicator function is used in the baacktest, the function will be automatically shown in the chart, and buying and selling also will be marked;
  • 11.service fee setting;
  • 12.adding platforms - trading pair & assests;
  • 13.backtest parameter settings; if the parameters are numbers and also support one-key optimizaton, the parameters will be traversed automatically in a certain range in the backtest.

Differences Between Bot & Backtest

  • 1.the only valid market quotes in the backtest are only from GetTicker and GetRecords; others like GetDepth and GetTrades are not real (the data volume is huge, and although the real market level backtest now supports the data already, it only supports the latest data);
  • 2.the platforms added in the backtest are all segregated accounts; right ow switching the trading pairs is not supported; therefore, you cannot operate two trading pairs in one account;
  • 3.netwrok request cannot be used in the backtest;
  • 4.IO extension cannot be used in the backtest, and only basic APIs can be operated;
  • 5.only standard data can be obtained in the backtest, and the data, like Info that is related to the bot, does not exist;
  • 6.tarding might be not executed in the backtest, and pay attention to the situation of frozen orders;
  • 7.in the backtest of commodity futures, market order is not supported.

Strategy Fault Tolerance & Common Errors

As we mentioned earlier, Using an API interface in the bot may fail to access and return null; if you still use the data of it, an error will be reported and the bot will stop. Therefore, strategies need to do well in fault tolerance.

Common Ways of Fault Tolenrance

Common Causes:

  • API access network error; the timeout of accessing the interface returns nunll, and an error will be reported.

  • Platfrom limitation error, such as ip limitation, order precision, access frequency, parameter error, asset deficiency, market trading failure, the canceling of executed orders, etc.; the details can be queried in the API document according to the wrong codes.

  • Platform return data error; it happens sometimes, such as returning null depth, delayed account information and delayed order status, etc.

  • Program logic error.

Before you use the returned data of API, you should judge whether the data is null, and the common methods are introduced as follows:

//1.judge the data is null and handle 
var ticker = exchange.GetTicker();
while(ticker == null){
     Log('ticker obtain error');
     ticker = exchange.GetTicker();
 }
 Log(ticker.Last);
 // 2. judge the data is not null, and use 
 var ticker = exchange.GetTicker();
 if(!ticker){
     Log(ticker.Last);
 }
 // 3.retry _C() function 
 var ticker = _C(exchange.GetTicker);
 Log(ticker.Last);
 // 4.try cache fault tolerance
 try{
     var ticker = exchange.GetTicker();
     Log(ticker.Last);
 }
 catch(err){
     Log('ticker obtain error');
 } 

If you want to obtain the information of erors, you can use GetLastError(), and the strings of the last time error information will be returned, and the errors can be processed by differences.

FAQ

Common error summary in the top posts of the forums: https://www.fmz.com/bbs-topic/9158. Here we introduce it in brief; you can use ctrl+F to search, when you have problems.

How to deploy the docker?

There is a detailed introdution about it in the section of adding a docker.

Can I ask someone to ghostwrite strategies for me?

on https://www.fmz.com/markets , there are some people who provide services of writing strategies for others, or you can ask in the chatting groups; notice that those kind of services shall be contacted by yourself, and you should be aware that the risk shall also be borne by yourself.

All interfaces prompt timeout when acessed

it refers to the timeout of the accessed platform interface; if the timeout happens occasionally, it is not a problem; if the timeout is prompted all the time, that means all networks cannot be accessed and an overseas server is needed.

ERR_INVALID_POSITION

If the backtest reports an error, it is generally a writing error; when you try to place an order to close a position, when there is no position or the position volume is not enough, an error will be reported.

Symbol not set

There is no contract set in the code, durig the backtests of futures platforms. Refer to exchange.SetContractType function.

BITMEX 429error,{“error”:{“message”:“Rate limit exceeded retry in 1 seconds ……”}}

The access frequency of the platform interface is too high.

{“status”:6004,“msg”:“timestamp is out of range”}

The timestamp of the server exceeds the time range of updating the server, and the exceeded time cannot be too long.

GetOrder(455284455): Error: invalid order id or order cancelled.

If the order of a platform is cancelled, the platform will not maintain the order information anymore, so the information cannot be obtained.

GetOrders: 400: {“code”:-1121,“msg”:“Invalid symbol.”}

Invalid trading pair; check out if the tradig pair setting is wrong.

Secret key decrypt failed

The APIKEY parsing fails. If the FMZ password has been modified after the APIKEY is configured, try to add a platform page on FMZ and reconfigure the platform APIKEY.

Signature not valid: invalid submission time or incorrect time format

suggest you use Linux server, or install time synchronization software on these Windows systems where this problem occurs.

Why the docker still cannot access the platform API when a global proxy is set?

The global proxy does not have a proxy docker network port. Due to the delay problem, it is best to deploy the docker of an overseas server.

How to save a strategy locally, not to upload it to FMZ?

Using Python, and you can import local files, save the strategy normally written by FMZ API as a file and put it in the execution path on your own server, and you can directly read and execute it.

#!python2.7

def run(runfile):
      with open(runfile,"r") as f:
            exec(f.read())
            
def main():
    run('my.py')

How to the testnet of a platform or how to change API base address?

Use exchange.SetBase() to directly switch to the corresponding API base address. For example:

exchange.SetBase("https://www.okex.me")

More