[TOC]

Basic Instructions

Getting Started

What can FMZ Quant Trading Platform do?

FMZ Quant Trading platform is the most professional quantitative community in the field of quantitative trading. Here you can learn, write, share, buy and sell quantitative strategies; you can conduct online backtesting and use simulation bots to conduct simulated trading; you can also run, publicize, and watch live trading. We support almost all mainstream digital currency exchanges.

Complete Series of Tutorials

Graphic Tutorials:

If there is any problem, you can post questions and discuss in the forum at any time, or submit a ticket, or contact an administrator in the Telegram group (Telegram), generally speaking, the question will be answered quickly.

Supporting ChatGPT for development assistance

FMZ Quantitative Trading Platform has adopted ChatGPT as a development assistance tool, which can be accessed by clicking “ChatGPT” in the shortcut bar in the “Dashboard” to jump to the ChatGPT Auxiliary Tool Page.

Which programming languages are available to implement my strategies?

FMZ Quant Trading platform supports to use JavaScript, TypeScript, Python, C++, Pine Mylanguage and Blockly Visualization to write and design strategies.

It supports TypeScript language, still set it to JavaScript strategy when we create strategies, then we write // @ts-check at the beginning of the strategy code or click the button TypeScript in the top right corner of the strategy editing area to switch to TypeScript. The platform will recognize the code as TypeScript automatically and provide you with the appropriate compilation and type checking support for:

  • Type safety: TypeScript's static type checking function can help you find potential errors when writing code and improve code quality.
  • Automatic code completion: TypeScript's type system makes it faster to find the attributes and methods you need when writing code, improving development efficiency.
  • Clearer code structure: With TypeScript, you can better organize and maintain your code, making it easy to read and understand.
  • Powerful object-oriented programming features: TypeScript provides powerful object-oriented programming features, such as interfaces, classes, generics and so on, helping you write more robust and reusable strategy code.

You only need to master one of these languages. In addition to supporting the way of designing strategies by writing code, you can also create strategies using visual modules (Blockly). The visualization module splicing and building strategy, without coding, adopts a more intuitive way to design strategies, which is very suitable for cultivating interest in strategy design so as to quickly get started with programmatic and quantitative trading.

Blockly Visualization Tutorials:

Set the Python interpreter used by the Python strategy program

Strategies written in Python, when backtesting or live trading, if the docker system environment has bothPython2 and Python3 installed, you can set the Python version to be launched at runtime on the first line of the strategy, such as #!python3 and #!python2, so that the system will find the interpreter automatically. And you can also specify an absolute path, such as: #!/usr/bin/python3.

What is Docker?

Docker can be understood as the executor of your trading strategy, responsible for complex data requests, data reception, network links, log postback and so on. The docker runs on your server, even if the FMZ Quant Trading platform website has a network failure, it will not affect the operation of your docker. The docker can run on Linux, Windows, Mac OS, Android, Raspberry Pi ARM Linux and other systems. Docker Page, Linux docker installation and update steps. The bots and logs managed by the docker are stored in the directory /logs/storage. The file is a Sqlite database file with db3, which can be edited directly by the Sqlite management software. For a file with extension db3 in the real bot database, the file name is the bot ID.

Protocols Supported

  • Blockchain Assets: More than 50 mainstream blockchain assets (cryptocurrency) exchanges are now supported in our platform.
  • General Protocol Access: general protocol

Strategy Security

When trading strategies are developed on FMZ Quant Trading platform, the strategy contents are only visible to the FMZ account holders. And on the FMZ quantitative trading platform, you can achieve complete localization of strategy code. For example, a strategy logic can be encapsulated into a Python package, which is loaded in the strategy code, so that the strategy content localization can be realized.

The security of Python code: Because Python is an open-source language that is extremely easy to decompile, if the strategy is not for personal use but for rent, you can run the strategy on your own deployed docker and rent it out in the form of sub-account or full docker management if you are worried about strategy leakage.

The encryption of Python strategy code: By default, Python strategy code is not encrypted when used by the author and encrypted when rented to others. By editing the following code at the beginning of the Python strategy, you can specify whether to encrypt the strategy code for personal use or rental. The Python versions that support the encryption of strategy codes are as follows: Python 2.7, Python 3.5 and Python 3.6.

  • Strategy authors run it themselves and encrypt the strategy code for others to use through registration code: Specify #!python as the version of Python interpreter, and then use , to keep apart; input the encryption command encrypt. If you don’t specify the version of Python, add #!,encrypt directly.
 #!python,encrypt

Or

  #!encrypt
  • It will not encrypt the strategy codes when strategy writers run for their own use and share with others through the registration code:
  #!python, not encrypted

Or

  #!not encrypted

Use code os.getenv('__FMZ_ENV__') to determine whether the encryption code is valid; the return of the string "encrypt" indicates that it has taken effect. It is only valid in the real bot, and the backtest will not encrypt the Python strategy codes.

#!encrypt
def main():
    ret = os.getenv('__FMZ_ENV__')
    # If the print variable ret is the string "encrypt" or ret == "encrypt" is true, that means the encryption is valid. 
    Log(ret, ret == "encrypt")

Key Security

The sensitive data, such as account information and encrypted strings in strategy parameters configured on the FMZ Quant Trading platform, are encrypted at the web browser. All information stored on FMZ Quant Trading platform is encrypted (not plaintext data), and only users’ private devices can decrypt and use the information, which greatly improves the security of sensitive data. Please do not disclose or sell the strategies if other sensitive information is included in the strategy code, parameter settings and strategy descriptions etc.

  • Our platform supports localized configuration of sensitive information, such as exchange account information and secret key On the page where the platform configures exchange information, all encrypted text box controls with masks support the way of configuring the file path to load the docker’s local file. The following takes the RSA KEY authentication method of the exchange as an example to explain in detail how to configure sensitive information locally on the device where the docker program is located.
  1. Create RSA public key and private key. For example, create public and private keys in the format of PKCS#8, there are many tools available for creation, such as openssl.
  2. Create an RSA KEY on the exchange, and upload the public key created in Step 1 during creation.
  3. Save the private key created in Step 1 in the same directory of the docker in the format of txt file, or in other paths in the directory of the docker program.
  4. When configuring the exchange on the FMZ platform, fill in the RSA KEY created by the exchange in the edit box of the configuration Access Key.
  5. When configuring the exchange on the FMZ platform, fill in the path of the txt file placed in the same level directory of the docker in the Step 3 in the edit box of the configuration Secret Key. For example, if the file name placed is: rsaKey.txt, and the file and the docker are filled in the same level directory: file:///rsaKey.txt. If the file is in the directory next to the directory of the docker program rsa_key, fill in: file:///rsa_key//rsaKey.txt. If you place rsaKey. txt elsewhere on your computer or server follow these instructions accordingly, it should be noted that this file can only be placed at either same-level directories or subdirectories with respect to docker.

This makes it safer to localize and save the private key, you can refer to video explanation for detailed process.

Backtest System

What is a backtest system, and what is it used for?

After you have accomplished the design of a quantitative trading strategy, how can you know the basic situation of your strategy, such as the logic of the strategy and the direction of the strategy’s returns? Of course, we cannot use real money directly to run the strategy on the real trading market, but we can use historical data to test your strategy and know the profits of your strategy in the historical data.

Is the backtest system data accurate and how about the accuracy of the backtest results?

FMZ Quant Trading platform divides the backtest system into real market level and simulation level. The real market level is to backtest completely according to the complete historical data; while simulation level backtest generates tick data according to the real K-line data at regular intervals for backtest. They are both based on the real historical data, but the real market level data is more accurate and the results are more credible. FMZ Backtest Mechanism Description. However, backtesting is just the performance of the strategy according to historical data. The historical data cannot fully represent the future market. The historical market may repeat, or it may also lead to the Black Swan. Therefore, the backtest results should be treated rationally and objectively.

Issues to be aware of when backtesting different programming language strategies:

The backtest of JavaScript and C++ trading strategies is conducted in the browser, and the real market bot or WexApp emulated exchange real market (i.e. the WexApp emulated exchange of FMZ Quant Trading platform) runs without installing any other software, libraries or modules. The backtest of Python is performed on the docker; it can be performed on the public server added by FMZ Quant Trading platform, and it can also be performed on user’s own docker. The real market operation and backtest both rely on the Python installed on the system where the docker is located. If some libraries are needed, they need to be installed manually (only common libraries are supported on public servers).

Backtest Data in the System

There are two types of FMZ Quant Trading platform backtest: simulation level backtest and real market level backtest. The simulation level backtest generates the simulated tick based on the underlying K-line period. Each K-line period will generate 12 backtesting time points; however, the real market level collects ticks actually, which will occur about once every few seconds, resulting in a large amount of data and slower backtest speed; so it cannot be backtested for a very long period of time. The backtest mechanism of FMZ allows the trading strategy to trade multiple times on a single K-line, avoiding the situation where the trading can only be executed at the close price. It is more accurate while taking into account the speed of backtest. For more detailed explanations, please refer to the Link.

Strategy DEBUG method in the backtesting system

JavaScript strategy backtesting debugging in Chrome DevTools

Exchanges Supported in the Backtesting System

  • Encrypted Currency (Cryptocurrency)

    Name Type Instruction
    Bitfinex spot exchange object supporting limited trading pairs, such as: BTC_USD, ETH_USD and LTC_USD, etc. (notice the quote currency of the trading pairs is USD dollar)
    Binance spot exchange object supporting limited trading pairs, such as: BTC_USDT, ETH_USDT, ETH_BTC and LTC_BTC, etc.
    OKX spot exchange object supporting limited trading pairs, such as: BTC_USDT, ETH_USDT, ETH_BTC and LTC_BTC, etc.
    Huobi spot exchange object supporting limited trading pairs, such as: BTC_USDT, ETH_USDT, ETH_BTC and LTC_BTC, etc.
    OKX Futures futures exchange object supporting limited trading pairs, such as: BTC_USD and ETH_USD, etc.; the quote currency of the trading pairs is USD; after the setting of specific contract code (please refer to the function exchange.SetContractType), the contract is crypto-margined contract; the supported contract codes include: this_week, next_week, quarter and swap
    HuobiDM futures exchange object HuobiDM is Huobi Futures (Huobi Contract), supporting limited trading pairs, such as: BTC_USD and ETH_USD,etc.; the quote currency of the trading pairs is USD; after the setting of specific contract code (please refer to the function exchange.SetContractType), the contract is crypto-margined contract; the supported contract codes include: this_week, next_week, quarter and swap.
    BitMEX futures exchange object the trading pair is XBT_USD; after the setting of specific contract code (please refer to the function exchange.SetContractType), the contract is a crypto-margined contract; the supported contract code is: XBTUSD
    Binance Futures futures exchange object supporting limited trading pairs, such as: BTC_USDT and ETH_USDT, etc.; the quote currency of the trading pairs is USD; after the setting of specific contract code (please refer to the function exchange.SetContractType), the contract is a USDT - margined contract; the supported contract code is swap
    Deribit Options futures exchange object trading pairs are: BTC_USD and ETH_USD; after the setting of specific contract code (please refer to the function exchange.SetContractType), the contract is a crypto-margined contract; specific options contract codes need to be set

    For the futures exchange objects in the backtest system, changing trading pairs is temporarily not supported in the strategy codes.

Simulation Level

The simulation level backtest is based on the underlying K-line data of the backtest system, simulating tick data within the framework of the highest price, lowest price, opening price, and closing price values ​​of a given underlying K-line Bar according to a certain algorithm. The data will return real-time tick data when the interface is requested. For details, please refer to: FMZ Quant Simulation Level Backtest Mechanism Description.

Real Market Level

The real market level backtest is the actual tick level data in the Bar time series. For strategies based on tick level data, using real market level to backtest is closer to reality. In real market level backtest, tick data is real recorded data, not simulated one. It supports depth data, record data playback of market tradings, custom depth and each individual trading data. The maximum size of the real-market-level data backtest is up to a maximum of 50MB, with no limit on the backtest time range within the upper limit of the dataset. If you need to enlarge the backtest time range as much as possible, you can reduce the value of the depth gear setting and do not use each individual trading data to increase the backtest time range. Call GetDepth,GetTrades functions to obtain playback market data. At a moment of market data on the timeline, calling GetTicker,GetTrades, GetDepth and GetRecords will not push the time multiple times when the time moves on the backtest timeline (which will not trigger a jump to the next market data moment). Repeated calls to one of the above functions will push the backtest time to move on the backtest timeline (jump to the next market data moment). When the real market level is used for backtest, an earlier time is not recommended to choose. There may be no real-market-level data in the premature time period.

The real market level backtest currently supports:

  • Binance
  • OKX (OKX Spot)
  • HuobiDM (Huobi Futures)

Backtesting System Parameter Optimization

The parameters optimization function of the backtest system of FMZ Quant Trading platform is to set optimizations according to every parameter optimization option during backtest, and the options are shown as follows:

  • Minimum value: to limit the start value of the parameters.
  • Maximum value: to limit the maximum value of the parameters after incremental changes.
  • Step size: the incremental variable amount of the parameters.

Generate parameters combinations, and traverse all those combinations to backtest (namely backtesting each parameters combination once). Only strategy parameters of number type can be optimized in the backtesting system.

For example, set parameters optimization options on the backtest page:

img

The backtest of parameters optimization mode:

img

Save Backtest Settings

In the strategy editing page, in the pagination of “Backtest” (namely the backtest system), you can set options like backtest configurations and strategy parameters to backtest the strategy. Backtest settings refer to backtest time range, exchange platform, slippoint and service fee etc.; while strategy parameters are used to set parameter options for strategies. When the strategy configurations are all set, you can backtest the strategy according to the settings. So how do you save these configured settings for use in the next backtest (the options set during page refresh will be reset)? You can click the “Save Settings” button on the strategy page, and all backtest settings (including backtest configurations and strategy parameter settings) will be recorded in code form in the source code of the strategy. When opening the strategy editing page again and switching to the backtesting system, the recorded backtesting configuration information in the strategy code will be automatically configured on the backtesting page.

img

Take JavaScript strategy as an example, and click “Save Backtest Settings to Source File”:

img

There are slight differences on “Save Backtest Settings to Source File” among JavaScript, Python, cpp and Mylanguage:

/*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
platforms: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
'''backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
platforms: [{"eid":"Binance","currency":"BTC_USDT"}]
'''
/*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
platforms: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

Mylanguage:

(*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
platforms: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
*)

Custom Data Source

The system uses the GET method to request a custom URL (publicly accessible URL) to obtain an external data source for backtest. The additional request parameters are as follows:

Parameter Meaning Explanation
Symbol Symbol Name such as BTC_USD_OKCoin_EN
Eid Exchanges such as OKCoin_EN
Round Price Accuracy such as 3, the price in the returned data must be multiplied by 1000 and rounded
Vround Quantity Accuracy such as 2, the amount in the returned data must be multiplied by 100 and rounded
Period Bar Period (Milliseconds) such as 60,000 indicating the bar requesting one minute
Depth Depth Levels 1-20
Trades Whether Need to Split Data true/false
From Start Time unix timestamp
To End Time unix timestamp

Note:

Round and V-Round are two parameters designed to avoid losing the precision of floating-point numbers during network transmission. The price data, trading volume and order amount, are all transmitted using integers.

An example of the stitched data:

http://customserver:80/data?symbol=BTC_USD_OKCoin_EN&eid=OKCoin_EN&round=3&vround=3&period=900000&from=1564315200&to=1567267200

The returned format must be one of the following two formats (which will be recognized by the system automatically):

Ordinary Bar-Level Backtest

{
    "schema":["time","open","high","low","close","vol"],
    "data":[[1564315200000,9531300,9531300,9497060,9497060,787],[1564316100000,9495160,9495160,9474260,9489460,338]]
}

Tick-level backtest data (including market depth information, an array with a depth format of [price,volume]; there can be multiple levels of depth; “asks” refers to price ascending order, and “bids” refers to price reverse order.)

{
    "schema":["time","asks", "bids","trades","close","vol"],
    "data":[[1564315200000,[[9531300,10]], [[9531300,10]],[[1564315200000,0,9531300,10]],9497060,787]]
}

Description

Field Description
Schema It specifies the attributes of the columns in the data array, which is case sensitive and is only limited to “time”, “open”, “high”, “low”, “close”, “vol”, “asks” and “bids”
Data An array that stores data by schema

Data Format

Field Description
asks/bids [[price,volume],…]
trades [[time,direction(0:buy,1:sell),price,volume],…]

Providing funding rate data:

For example, when backtesting Binance Futures, it is necessary to have additional data of funding rate, which needs to be provided by custom data source. For example, the data structure of the funding rate requested during the backtest of Binance Futures is shown as follows:

{
  "detail": {},
  "symbol": "futures_binance.eth_usdt.funding",
  "schema": ["time", "open", "high", "low", "close", "vol"],
  "data": [
    [1582876800000, 25289, 25289, 25289, 25289, 0],
    [1582905600000, 30522, 30522, 30522, 30522, 0],
    [1582934400000, 40998, 40998, 40998, 40998, 0],
        ...
    [1626652800000, 198, 198, 198, 198, 0],
    [1626681600000, 691, 691, 691, 691, 0],                  // The adjacent periodic interval is 8 hours
    [1626710400000, 310, 310, 310, 310, 0],                  // The funding rate of Binance updates every 8 hours, and why the data of the funding rate turns out to be 310?
    [1626739200000, 310, 310, 310, 310, 0],                  // Like the bars data, to avoid losing the precision of floating-point numbers during network transmission, the data uses integer, so the data needs to be processed according to round parameter; the data, returned to the backtest system after processing, is 310 
    [1626768000000, -41610, -41610, -41610, -41610, 0],      // The funding rate might be a negative value
    [1626796800000, -5125, -5125, -5125, -5125, 0],
        ...   
    [1627977600000, 10000, 10000, 10000, 10000, 0]
  ]
}

An example of the data request from the backtest system:

http://customserver:80/data?symbol=futures_binance.eth_usdt.funding&eid=Futures_Binance&round=8&vround=5&depth=20&trades=1&custom=0&period=3600000&from=1360771200&to=1628006400

Example for Custom Data Source:

Specify the data source, URL: http://xxx.xx.x.xx:9090/data Customize the data server, written in golang:

package main 
import (
    "fmt"
    "net/http"
    "encoding/json"
)

func Handle (w http.ResponseWriter, r *http.Request) {
    // e.g. set on backtest DataSourse: http://xxx.xx.x.xx:9090/data
    // r.URL: /data?depth=20&detail=true&eid=Binance&from=1566820800&period=900000&round=3&symbol=BTC_USDT_Binance&to=1569686400&trades=1&vround=5
    // response
    defer func() {
        // response data
        /* e.g. data
        {
            "schema":["time","open","high","low","close","vol"],
            "data":[
                [1564315200000,9531300,9531300,9497060,9497060,787],
                [1564316100000,9495160,9495160,9474260,9489460,338]
            ]
        }
        */
        ret := map[string]interface{}{
            "schema" : []string{"time","open","high","low","close","vol"},
            "data" : []interface{}{
                []int64{1564315200000,9531300,9531300,9497060,9497060,787},
                []int64{1564316100000,9495160,9495160,9474260,9489460,338},
            },
        }
        b, _ := json.Marshal(ret)
        w.Write(b)
    }()
}

func main () {
    fmt.Println("listen http://localhost:9090")
    http.HandleFunc("/data", Handle)
    http.ListenAndServe(":9090", nil)
}

Testing strategy, JavaScript example:

/*backtest
start: 2019-07-28 00:00:00
end: 2019-07-29 00:00:00
period: 1m
platforms: [{"eid":"OKX","currency":"BTC_USDT","feeder":"http://120.24.2.20:9090/data"}]
*/

function main() {
    var ticker = exchange.GetTicker()
    var records = exchange.GetRecords()
    Log(ticker)
    Log(records)
}

Charts drawn by the custom data in the backtest system:

Strategy Print Information:

Local Backtest Engine

FMZ Quant Trading platform has open-sourced for the JavaScript version and the Python version of the local backtest engine, supporting setting Underlying K Line Period during backtesting.

Backtest Page Shortcut Keys

  • Shortcut key for switching between strategy “Editing” page and the “Backtesting” page

    Use the key Ctrl +, to switch back to “Backtest” page and “Edit Strategy” page. After hold down the key Ctrl, press the key ,.

  • Shortcut key for saving strategy

    Use the key Ctrl + s to save strategies.

  • Shortcut for starting strategy backtest

    Use the key Ctrl + b to enable “Start Backtest”.

Code Description

Entry Functions

Function Name Description
main() it is an entry function.
onexit() it is a cleanup function when exiting normally, its maximum execution time is 5 minutes, which can be left undeclared; if the timeout occurs, an interrupt error will be reported.
onerror() it is an abnormal exit function, its maximum execution time is 5 minutes, which can be left undeclared. The strategies written in Python and cpp don’t support this function.
init() it is an initialization function, its strategy program will be called automatically when it starts running, which can be left undeclared.
  • Description:
    1. The backtest system doesn’t support the function onerror().
    1. If the function onerror() is triggered in the bot, the function onexit() will not be triggered.

onexit()

onexit(), processing clean-up work, with a maximum execution time of 5 minutes, which is realized by the user.

function main(){
    Log("Start running, stop after 5 seconds, and execute onexit function!")
    Sleep(1000 * 5)
}

// onexit function implementation
function onexit(){
    var beginTime = new Date().getTime()
    while(true){
        var nowTime = new Date().getTime()
        Log("The program stops counting down..The cleaning starts and has passed:", (nowTime - beginTime) / 1000, "Seconds!")
        Sleep(1000)
    }
}
import time 
def main():
    Log("Start running, stop after 5 seconds, and execute onexit function!")
    Sleep(1000 * 5)

def onexit():
    beginTime = time.time() * 1000
    while True:
        ts = time.time() * 1000
        Log("The program stops counting down..The cleaning starts and has passed:", (ts - beginTime) / 1000, "Seconds!")
        Sleep(1000)
void main() {
    Log("Start running, stop after 5 seconds, and execute onexit function!");
    Sleep(1000 * 5);
}

void onexit() {
    auto beginTime = Unix() * 1000;
    while(true) {
        auto ts = Unix() * 1000;
        Log("The program stops counting down..The cleaning starts and has passed:", (ts - beginTime) / 1000, "Seconds!");
        Sleep(1000);
    }
}

init()

The user implements the initialization function init(), which will automatically execute the function init() at the beginning of the strategy to complete the initialization task.

function main(){
    Log("The first line of the code executed in the program!", "#FF0000")
    Log("Exit!")
}

// Initialization Function
function init(){     
    Log("Initialization!")
}
def main():
    Log("The first line of the code is executed!", "#FF0000")
    Log("Exit!")

def init():
    Log("Initialization!")
void main() {
    Log("The first line of the code is executed!", "#FF0000");
    Log("Exit!");
}

void init() {
    Log("Initialization!");
}

onerror()

The execution of function onerror() will be triggered, when an exception occurs. This function does not support strategies written inPython and cpp.

function main() {
    var arr = []
    Log(arr[6].Close)
}

function onerror() {
    Log("error")
}
# not supported by python 
// not supported by C++ 

Classic Strategy Framework

In the strategies written in JavaScript, Python and cpp, the Sleep() function needs to be called in the main loop of those strategies. It will be used to control the backtracking speed. In the bot, it is used to control the strategy polling intervals, and also control the requesting frequency of accessing the API interface of the exchange.

  • Basic framework examples of cryptocurrency strategies:

    function onTick(){
        //Write strategy logic here, and it will be called constantly, such as printing market information
        Log(exchange.GetTicker())
    }
    
    function main(){
        while(true){
            onTick()
            //The function "Sleep" is mainly used to control the polling frequency of cryptocurrency strategies to prevent accessing the exchange API interafce too frequently 
            Sleep(60000)
        }
    }
    
    def onTick():
        Log(exchange.GetTicker())
    
    def main():
        while True:
            onTick()
            Sleep(60000)
    
    void onTick() {
        Log(exchange.GetTicker());
    }
    
    void main() {
        while(true) {
            onTick();
            Sleep(60000);
        }
    }
    

    Take the simplest example, if I want to place a buy order with a price of 100 and a quantity of 1 on the exchange every second, I can write it like this:

    function onTick(){
        // It is just an example; for all the assets will be used to place orders fast during backtest or in the bot, do not implement the example in the bot
        exchange. Buy(100, 1)
    }
    
    function main(){
        while(true){
            onTick()
            // The pause period can be customized in millisecond (1 second = 1000 milliseconds)
            Sleep(1000)
        }
    }
    
    def onTick():
        exchange.Buy(100, 1)
    
    def main():
        while True:
            onTick()
            Sleep(1000)
    
    void onTick() {
        exchange.Buy(100, 1);
    }
    
    void main() {
        while(true) {
            onTick();
            Sleep(1000);
        }
    }
    

Template library

The template library is a reusable code module in FMZ Quant Trading platform, working as a category of trading strategy codes. When creating a trading strategy, if the category is set to Template library, a template is added in the “Strategy” page of the account that currently logged in FMZ Quant Trading platform. After creation, it is no longer possible to modify the category to a normal strategy.

“Template library” in JavaScript:

img

“Template library” in Python:

img

“Template library” in cpp:

img

  • Export function of “Template library” The export function is an interface function of “Template library”, and it can be called by the strategy that refers to “Template library”. The example code for the declaration and implementation of the exported function in the Template library is as follows:

    /*
    -- This method is called directly with $.Test() after the strategy refers to the template
    -- The "main" function will not be triggered in the strategy, and it is only used as the entry point for template debugging
    */
    $.Test = function() {
        Log('Test')
    }
    
    function main() {
        $.Test()
    }
    
    def Test():
        Log("template call")
    
    # Export "Test" function; the main strategy can be called by ext.Test()
    ext.Test = Test 
    
    // The strategy refers to the template and calls this method directly with ext::Test()
    void Test() {
        Log("template call");
    }
    
  • “Template library” parameters “Template library” can also set its own interface parameters, which are used in the form of global variables in the code of “Template library”.

    “Template library” parameter settings:

    img

    Template library codes:

    $.SetParam1 = function(p1) {
        param1 = p1
    }
    
    $.GetParam1 = function() {
        Log("param1:", param1)
        return param1
    }
    
    def SetParam1(p1):
        global param1
        param1 = p1
    
    def GetParam1():
        Log("param1:", param1)
        return param1
    
    ext.SetParam1 = SetParam1
    ext.GetParam1 = GetParam1
    
    void SetParam1(float p1) {
        param1 = p1;
    }
    
    float GetParam1() {
        Log("param1:", param1);
        return param1;
    }
    

    Refer to the strategy code in the Template library example mentioned above:

    function main () {
        Log("call $.GetParam1:", $.GetParam1())
        Log("call $.SetParam1:", "#FF0000")
        $.SetParam1(20)
        Log("call $.GetParam1:", $.GetParam1())
    }
    
    def main():
        Log("call ext.GetParam1:", ext.GetParam1())
        Log("call ext.SetParam1:", "#FF0000")
        ext.SetParam1(20)
        Log("call ext.GetParam1:", ext.GetParam1())
    
    void main() {
        Log("call ext::GetParam1:", ext::GetParam1());
        Log("call ext::SetParam1:", "#FF0000");
        ext::SetParam1(20);
        Log("call ext::GetParam1:", ext::GetParam1());
    }
    

    img

  • Quote “Template library”

    After checking the reference in the template column of the strategy editing page, save the strategy.

    img

Built-In Structure

Global Variables

Exchange

Exchangecan be regarded as an exchange object. By default, it is regarded as the first exchange object added in the strategy parameters. All data interaction with the exchange is realized through the functions in this object.

  • Adding exchange objects in “Backtest”

  • Adding exchange objects on “Bot” page

The added exchange objects correspond to the exchange objects in the code:

function main() {
    Log("The name of the first exchange object added on the bot page or backtest page:", exchange.GetName(), ", Label:", exchange.GetLabel())
}
def main():
    Log("The name of the first exchange object added on the bot page or backtest page:", exchange.GetName(), ", Label:", exchange.GetLabel())
void main() {
    Log("The name of the first exchange object added on the bot page or backtest page:", exchange.GetName(), ", Label:", exchange.GetLabel());
}
Exchanges

It can be understood as an array that stores all exchange objects like exchange exchange objects, which may contain multiple exchange objects; exchanges[0] is exchange.

The added exchange objects correspond to exchanges[0], exchanges[1], exchanges[2] … and so on in the strategy code.

function main() {
    for(var i = 0; i < exchanges.length; i++) {
        Log("Index of the exchange object added (the first one is 0 and so on):", i, "Name:", exchanges[i].GetName(), "Label:", exchanges[i].GetLabel())
    }
}
def main():
    for i in range(len(exchanges)):
        Log("Index of the exchange object added (the first one is 0 and so on):", i, "Name:", exchanges[i].GetName(), "Label:", exchanges[i].GetLabel())
void main() {
    for(int i = 0; i < exchanges.size(); i++) {
        Log("Index of the exchange object added (the first one is 0 and so on):", i, "Name:", exchanges[i].GetName(), "Label:", exchanges[i].GetLabel());
    }
}
Order Status

The attribute Status in the Order structure.

Constant Name Definition Value
ORDER_STATE_PENDING unfinished 0
ORDER_STATE_CLOSED finished 1
ORDER_STATE_CANCELED canceled 2
ORDER_STATE_UNKNOWN unknown state (other states) 3

ORDER_STATE_UNKNOWN status can call exchange.GetRawJSON() to get the original order status information, query the exchange file, and view the specific description. The constant names in the form can be used directly in the strategy code to compare with the attribute Status in the Order structure, to ensure the order status by judging if the they are equal. Printing those constant names will show the constant names and their corresponding values, and other constant names down below work in the same way, so there will be no more detailed descriptions about them.

Order Transaction Type

The attribute Type in the Order structure.

Constant Name Definition Value
ORDER_TYPE_BUY Buy Order 0
ORDER_TYPE_SELL Sell Order 1
Position Type

The attribute Type in the Position structure.

Constant Name Definition Description Applicable Value
PD_LONG Long Position Cryptocurrency futures use exchange.SetDirection("closebuy") to set the close position direction, and close this type of positions Cryptocurrency futures 0
PD_SHORT Short Position Cryptocurrency futures use exchange.SetDirection("closesell") to set the close position direction, and close this type of positions Cryptocurrency futures 1
Futures Opening & Closing Position Directions

The attribute Offset in the Order structure.

Constant Name Definition Value
ORDER_OFFSET_OPEN Open Position Orders 0
ORDER_OFFSET_CLOSE Close Position Orders 1
Strategy Parameters

In the trading strategy codes, the strategy parameters set on the strategy interface are reflected in the form of global variables. JavaScript language can directly access the parameter values set or modified on the strategy interface; while in the functions of Python strategies, the keyword global is needed to modify the global variables in the strategy.

Parameter Types:

img

Variable Description Remarks Type Default Value Description
Number Numeric type Remarks Number (number) 1 C++ strategy is a floating-point type
String string Remarks String (string) Hello FMZ The default value does not need to be quoted. The input is treated as a string
Combox ComboBox Remarks ComboBox (selected) 1|2|3 The combox variable itself is a numerical value, which represents the index of the column selected by the Combobox control. The value of the first ComboBox is 1, and others is 0, and so on
Bool Check options Remarks Boolean (true/false) true If checked, the variable bool is true; if not checked, the variable bool is false
SecretString Encrypted string Remarks Encrypted String (string) Password With the same usage as a string, the encrypted string will be sent by encryption and will not be transmitted in plain text
  • Interface parameters are set in the strategy parameter section below the code editing section of the strategy editing page.
  • Interface parameters exist as global variables in the strategy code, that is, interface parameters can be modified in the code.
  • The variable names of the interface parameters in the strategy code (seen in the above form): number, string, combox, bool, secretString.
  • Description option: the names of the interface parameters on the strategy interface.
  • Remark option: the detailed description of the interface parameters; the description will be displayed when the mouse is hovering over the interface parameters.
  • Type option: the type of the interface parameters.
  • Default value option: the default values of the interface parameters.

Parameter Dependency Settings: One parameter can be set to allow another parameter to be displayed and hidden based on the selection of the parameter. For example, we set the parameter numberA, which is a numeric type. We let numberA be displayed or hidden based on whether parameter isShowA (boolean type) is true or false. We need to set the variable numberA on the interface parameters as: numberA@isShowA.

img

In this way, if the parameter isShowA is not checked, the parameter numberA is hidden. As for the parameters of ComboBox control type, the dependent part of the parameters is to judge whether the parameter value equals the index value of some option in the ComboBox. In the same way, take parameter isShowA as an example. When set the variables in the parameters, write: numberA@combox==2. The parameter numberA will display or hide, based on whether the parameter combox will be checked as the third option (where index 0 corresponds to the first option, index 1 corresponds to the second, and index 2 corresponds to the third.)

Strategy interface parameters, interactive controls, and parameter grouping function on “Template”: Just add (?First group) at the beginning of the description of the parameter that starts grouping, as shown in the following figure:

img

When you are using the strategy, the parameters are displayed in groups:

img

Save parameter default value: The strategy parameters are shown in the figure. During the backtest, if you want to save the default values of the strategy parameters, you can click the Save settings button after modifying the strategy parameters.

img

img

You can save the strategy parameter settings in form of code:

/*backtest
start: 2020-02-29 00:00:00
end: 2020-03-29 00:00:00
period: 1d
args: [["number",2],["string","Hello FMZ.COM"],["combox",2],["bool",false],["numberA@isShowA",666],["isShowA",true]]
*/
'''backtest
start: 2020-02-29 00:00:00
end: 2020-03-29 00:00:00
period: 1d
args: [["number",2],["string","Hello FMZ.COM"],["combox",2],["bool",false],["numberA@isShowA",666],["isShowA",true]]
'''
/*backtest
start: 2020-02-29 00:00:00
end: 2020-03-29 00:00:00
period: 1d
args: [["number",2],["string","Hello FMZ.COM"],["combox",2],["bool",false],["numberA@isShowA",666],["isShowA",true]]
*/

Data Structure

Some functions will be accompanied by the original JSON data requested during the call. The raw JSON data is stored in the attribute Info of the returned object. Since the backtest is not to access a platform interface, the returned data during the backtest has no attribute Info. The following is a description of the main attributes of each data structure.

Trade

Obtain all trading history (not itself), returned by the function exchange.GetTrades().

{
    Id      : 9585306,          // Trading record ID; if the exchange interface does not provide order ID, use the timestamp to fill in 
    Time    : 1567736576000,    // Time (Unix timestamp milliseconds)
    Price   : 1000,             // Price
    Amount  : 1,                // Volume
    Type    : 0                 // Order Type; refer to the order type in the constants; 0 is ORDER_TYPE_BUY, meaning the value of ORDER_TYPE_BUY is 0
}
Ticker

Market quotes are returned by the function exchange.GetTicker().

{
    Info    : {...},             // After requesting the platform interface, this attribute is not available in the raw data that the exchange interface responds to, during the backtest
    High    : 1000,              // Highest price; if the platform interface does not provide the 24-hour highest price, use sell price 1 to fill in 
    Low     : 500,               // Lowest price; if the platform interface does not provide the 24-hour lowest price, use buy price 1 to fill in 
    Sell    : 900,               // Sell price 1
    Buy     : 899,               // Buy price 1 
    Last    : 900,               // Last executed price
    Volume  : 10000000,          // Recent trading volume; in principle, the unit of spot trading volume is base currency, and the unit of futures trading volume is contract quantity. If the platform interface does not provide this kind of data, use the existing data of the platform interface to fill in; for instance, it might be a trading volume in the unit of quote currency  
    Time    : 1567736576000      // Millisecond-level timestamp
}
Record

The standard OHLC structure is used to draw K-lines and process indicator calculation and analysis. The function exchange.GetRecords() returns the structure array. Each Record structure represents a k-line bar, namely one k-line BAR. The Time in the Record is the starting time of the K-line bar period.

{
    Time    : 1567736576000,     // A timestamp, accurate to millisecond, in the same format as the result obtained by Javascript's newDate().GetTime()
    Open    : 1000,              // Open price
    High    : 1500,              // Highest price
    Low     : 900,               // Lowest price
    Close   : 1200,              // Close price 
    Volume  : 1000000            // Trading volume; in principle, the unit of spot trading volume is base currency, and the unit of futures trading volume is contract quantity. If the platform interface does not provide this kind of data, use the existing data of the platform interface to fill in; for instance, it might be a trading volume in the unit of quote currency
}
Order

Order structure can be returned by functions, including exchange.GetOrder() and exchange.GetOrders(). The function exchange.GetOrders() returns the array or an empty array of the structure (if there is no current unfinished order, return [], namely, an empty array).

{
    Info        : {...},         // After requesting the platform interface, this attribute is not available in the raw data that the exchange interface responds to, during the backtest
    Id          : 123456,        // Unique ide