[TOC]
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:
TypeScript
's static type checking function can help you find potential errors when writing code and improve code quality.TypeScript
's type system makes it faster to find the attributes and methods you need when writing code, improving development efficiency.TypeScript
, you can better organize and maintain your code, making it easy to read and understand.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 thePython
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
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
.
#!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
#!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")
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.
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.PKCS#8
, there are many tools available for creation, such as openssl
.RSA KEY
on the exchange, and upload the public key created in Step 1 during creation.txt
file, or in other paths in the directory of the docker program.RSA KEY
created by the exchange in the edit box of the configuration Access Key
.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.
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
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.
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.
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:
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:
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:
The backtest of parameters optimization mode:
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.
Take JavaScript
strategy as an example, and click “Save Backtest Settings to Source File”:
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"}]
*)
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:
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.
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”.
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. |
onerror()
.onerror()
is triggered in the bot, the function onexit()
will not be triggered.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);
}
}
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!");
}
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++
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);
}
}
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
:
“Template library” in Python
:
“Template library” in cpp
:
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:
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());
}
Quote “Template library”
After checking the reference in the template column of the strategy editing page, save the strategy.
Exchange
can 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());
}
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());
}
}
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.
The attribute Type
in the Order
structure.
Constant Name | Definition | Value |
---|---|---|
ORDER_TYPE_BUY | Buy Order | 0 |
ORDER_TYPE_SELL | Sell Order | 1 |
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 |
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 |
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:
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 |
number
, string
, combox
, bool
, secretString
.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
.
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:
When you are using the strategy, the parameters are displayed in groups:
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.
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]]
*/
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.
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
}
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
}
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 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