[TOC]
What can the FMZ Quant platform do?
FMZ Quant platform (formerly known as BotVS) is the most professional quantitative trading community in China. Here you can learn, write, share, buy and sell quantitative trading strategies, backtest them online and use simulated trading market to simulate transactions. also you can run, open, and operate the real market from our platform’s excellent API connection. We mainly focus on almost all commonly used cryptocurrency exchanges, we also supports traditional Chinese commodity futures market.
A complete series of tutorials
Graphic Tutorial:
If you encounter any problem, you can post a question at the forum at any time, or send a work order, or in the Telegram group, QQ group and WeChat group @administrator, generally will be answered quickly.
Support:
Telegram Group https://t.me/fmzquant
QQ Group
WeChat Group
What programming languages are available to implement my strategy?
FMZ Quant supports JavaScript、Python、C++、M Language、Blockly Programming to write trading strategies. JavaScript Quick Start Python Quick Start M Language Quick Start.You only need to master one of these options. In addition to supporting writing code to write strategies, you can also use visualization modules to create strategies. The visualization module splicing construction strategy adopts a more intuitive way to design strategies without coding, which is very suitable for cultivating strategy design interest and getting started with quantitative trading.
Blockly Programming Tutorial:
What is a Docker?
Docker can be understood as the executor of your trading strategy, responsible for complex data requests, data reception, network links, log postbacks and more. The docker runs on your server, even if the FMZ website has a network failure, it will not affect the operation of your docker. The docker can be run on Linux, Windows, Mac OS, Android, Raspberry Pi and other system. Docker Page,Linux docker installation and update steps. The robots and logs managed by the docker are stored in the directory./logs/storage
, The file is a Sqlite database file of db3, which can be directly edited by the Sqlite management software. The file name is the robot ID.
Supported Exchanges
Blockchain assets: 50 mainstream blockchain assets (cryptocurrency) exchanges are now supported. Commodity futures: support CTP agreement, Esunny agreement and see-through supervision.
Special Exchange Notes:
BitMart
Since the authentication method is the OAuth 2.0
method, if two robots share the same API KEY, the two robots may continuously apply for tokens with each other (because data cannot be shared between robots), so for this exchange, it is recommended that each robot be configured with a separate API key.
Futures_Binance
Support Binance Futures two-way holding position mode, you can use exchange.IO
to switch:
function main() {
var ret = exchange.IO("api", "POST", "/fapi/v1/positionSide/dual", "dualSidePosition=true")
// ret : {"code":200,"msg":"success"}
Log(ret)
}
def main():
ret = exchange.IO("api", "POST", "/fapi/v1/positionSide/dual", "dualSidePosition=false")
Log(ret)
void main() {
auto ret = exchange.IO("api", "POST", "/fapi/v1/positionSide/dual", "dualSidePosition=true");
Log(ret);
}
When develop trading strategies on FMZ platform, the strategy contents are only visible to the FMZ account holders. Users also can deploying the strategy code completely localized. For example, a strategy logic can be packaged into a Python
package, which is loaded in the strategy code, so that the strategy content localization can be realized.
Security of Python code:
Because Python is an open source and easily decompilable language, if the strategy is not for own use but for rent, if you are worried about the strategy leakage, you can let the strategy run on the docker deployed by you and be managed in the form of sub-account or full hosting rent.
Python writing strategy code encryption:
By default, Python strategy code authors do not encrypt when they use it, but encrypt it when rented out to others. Edit the following code at the beginning of the Python strategy, you can specify whether to encrypt the strategy code when you use or rent out the strategy.
The Python versions that support strategy code encryption are various versions from Python 2.7
to Python 3.7
.
#!python
is to specify the version of the Python interpreter, then use comma ,
to enter the encryption command encrypt
. If you don’t specify the Python version, just add #!,encrypt
.
#!python,encrypt
Or
#!,encrypt
#!python,unencrypt
Or
#,unencrypt
To determine whether the encryption of the Python strategy code is effective, use os.getenv('__FMZ_ENV__')
, and return the string "encrypt"
, indicating that it has taken effect. Only the real market is valid, and the backtest will not encrypt the Python strategy code.
#!,encrypt
def main():
ret = os.getenv('__FMZ_ENV__')
# Print variable ret is the string encrypt or ret == "encrypt" is true, which means that the encryption takes effect
Log(ret, ret == "encrypt")
The sensitive information such as account information and encrypted strings in the strategy parameters configured on the FMZ platform are encrypted on the web browser side. The information stored on the FMZ platform are encrypted information (non-clear text data), Only the user’s private device can be decrypted, which greatly improves the security of sensitive data.
What is a backtest system and what is it for?
After you have completed the quantitative work of a 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 income? Of course, we cannot directly use real money to run strategies on the real trading market. We can use historical data to test your strategy and see how profitable your strategy is in historical data, whether it is losing money or making money.
Is the data of the backtest system accurate and the results credible?
FMZ divides the backtest system into real level and simulation level. The real level is backtested completely according to the complete historical data. The simulation level generates the k-line at regular intervals for backtesting. They both based on the real historical data, but the real level data is more accurate and the results are more credible. FMZ Backtest Mechanism Description. Backtest is just the performance of the strategy under historical data. Historical data does not fully represent the future market. The historical market may repeat itself or it may fly out of a black swan. So treat the backtest results rationally and objectively.
Factors need to pay attention when backtest different programming language written trading strategies:
JavaScript and C++ trading strategies. The backtesting is performed on the web browser end. The real market robot or simulation market robot (ie, the simulation market of BotVS) runs without installing any other software, libraries or modules. Python backtest is performed on the docker, and also can be backtested on the public server created by FMZ Quant. The real market operation and backtest both rely on Python installed on the system where the docker is located. If you need to use some libraries, you need to install them yourself (only common libraries are supported on public servers). When using a trading strategy written in Python, if the docker’s system environment has both Python2 and Python3 installed, you can set the version of Python by adding the code in the first line of the strategy code. Such as #!python3
, #!python2
, this will automatically find the right interpreter. You can also specify an absolute path, for example: #!/usr/bin/python3
.
Backtest Data
There are two types of FMZ platform backtest: simulation level backtest and real market level backtest. The simulation level backtest generates simulated ticks based on the underlying K-line period. Each K-line period will generate 14 backtesting time points, while the real market level is the actual collected “ticks”, which will occur once every few seconds. The amount of data It is very large and the backtesting speed is slow, so it cannot be backtested for a very long period of time. FMZ’s backtest mechanism allows the trading strategy to trade multiple times on a single K-line, avoiding the situation where the transaction can only be executed at the closing price. It is more accurate while taking into account the speed of backtest. For specific instructions, please refer to Link.
The simulation-level backtest is based on the underlying K-line data of the backtest system, and according to a certain algorithm, the ticker data is simulated in a frame composed of the highest, lowest, opening, and closing prices of the given underlying K-line Bar. Returned as real-time tick data when the interface is requested. For details, please refer to:FMZ Quant Simulation Level Back Test Mechanism Description.
The real market level backtest is the actual ticker level data in Bar’s time series. For strategies based on ticker-level data, using real market level backtesting is closer to reality. In Real market level backtesting, ticker is real recorded data, not simulation. Support depth data, market transaction record data playback, custom depth and each individual transaction data. The capability backtest data of the real market level is up to maximum of 50MB. The backtest time range is not limited within the upper limit of the data. If you need to increase the backtest time range as much as possible, you can reduce the value of the depth gear setting and do not use each individual transaction 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
,GetRecords
will not push the time multiple times when the time moves on the backtest timeline (does 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 use the real market level for backtesting, It is not recommended to choose a earlier time. There may be no real market level data in the premature time period.
The real market level backtest currently supports:
The system uses the GET method to request a custom URL (publicly accessible URL) to obtain an external data source for backtesting. The additional request parameters are as follows:
Parameter | Meaning | Explanation |
---|---|---|
Symbol | Symbol Name | For Example : BTC_USD_OKCoin_EN |
Eid | Exchange | eg: OKCoin_EN |
Round | Price Accuracy | as 3 then the price in the returned data must be multiplied by 1000 rounding |
vround | Quantity Accuracy | as 2 then the quantity in the returned data must be multiplied by 100 rounded |
Period | Bar Period (Milliseconds) | such as 60,000 for request minutes bar |
Depth | Depth Steps | 1-20 |
Trades | Whether Need To Split Data | true/false |
From | Start Time | Unix Timestamp |
To | End Time | Unix Timestamp |
Note:
Round and vround are two parameters designed to avoid loss of precision of floating-point numbers during network transmission. The numbers are transmitted using shaping.
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 the following two formats (any two formats can be returned, the system automatically recognizes):
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 (contains market depth information, an array of depth format is [Price,Volume], there can be multiple levels of depth, asks for ascending price, and bids for reverse price)
{
"schema":["time","asks", "bids","trades","close","vol"],
"data":[[1564315200000,[[9531300,10]], [[9531300,10]],[[1564315200000,0,9531300,10]],9497060,787]]
}
Description
Field | Description |
---|---|
Schema | specifies the attributes of the columns in the data array, which is case sensitive, only limit to time, open, high, low, close, vol, asks, bids |
Data | An array that stores data by schema |
Detail | Attributes Required for Commodity Futures |
detail Field
Field | Description | Examples |
---|---|---|
PriceTick | Price one pip jumping value | 0.1 |
VolumeMultiple | How many units in a lot | 100 |
ExchangeID | ExchangeID | CZCE |
LongMarginRatio | Long Margin Ratio | 0.2 |
ShortMarginRatio | Short Margin Ratio | 0.2 |
InstrumentID | Contract real market code | rb1906 |
Data Format
Field | Description |
---|---|
asks/bids | [[price,quantity],…] |
trades | [[time,direction(0:buy,1:sell),price,quantity],…] |
Custom data source example:
Specify the data source, URL:http://xxx.xx.x.xx:9090/data
Custom 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://localdocker:9090")
http.HandleFunc("/data", Handle)
http.ListenAndServe(":9090", nil)
}
Testing strategies, JavaScript examples:
/*backtest
start: 2019-07-28 00:00:00
end: 2019-07-29 00:00:00
period: 1m
exchanges: [{"eid":"OKEX","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 from custom data in the backtest system:
Strategies print information:
FMZ Quant trading platform has open sourced the JavaScript
version and the Python
version of local backtesting engine, and also supports setting Underlying K line cycle during backtest.
Shortcuts for switching between the strategy edit page and the strategy backtest page
Use the Ctrl +,
keys to switch back to the backtest page and the strategy editing page. After holding down the Ctrl
key, then press the ,
key.
Shortcuts for strategy edit saving
Use Ctrl + s
to save the edited code.
Shortcuts for strategy backtest
Use Ctrl + b
to start the backtest.
Function name | Description |
---|---|
main() |
as an entry function. |
onexit() |
As a normal exit tail sweep function, the maximum execution time is 5 minutes, which can be left unspecified. If the timeout occurs, an interrupt error will be reported. |
onerror() |
As an abnormal exit function, the maximum execution time is 5 minutes, which can be left unspecified. The strategy written in Python does not support this function. |
init() |
As an initialization function, the strategy program will be called automatically when it starts running, but it may not be declared. |
onerror()
.onerror()
function is triggered, the onexit()
function will not be triggered.Processing tail sweeping work, the maximum execution time is 5 minutes, which is realized by the user.
function main(){
Log("Start running, stop after 5 seconds, and execute the sweep function!")
Sleep(1000 * 5)
}
// Tail sweep function implementation
function onexit(){
var beginTime = new Date().getTime()
while(true){
var nowTime = new Date().getTime()
Log("The program stops counting down..The sweep starts and has passed:", (nowTime - beginTime) / 1000, "Seconds!")
Sleep(1000)
}
}
import time
def main():
Log("Start running, stop after 5 seconds, and execute the sweep function!")
Sleep(1000 * 5)
def onexit():
beginTime = time.time() * 1000
while True:
ts = time.time() * 1000
Log("The program stops counting down..The sweep starts and has passed:", (ts - beginTime) / 1000, "Seconds!")
Sleep(1000)
void main() {
Log("Start running, stop after 5 seconds, and execute the sweep function!");
Sleep(1000 * 5);
}
void onexit() {
auto beginTime = Unix() * 1000;
while(true) {
auto ts = Unix() * 1000;
Log("The program stops counting down..The sweep starts and has passed:", (ts - beginTime) / 1000, "Seconds!");
Sleep(1000);
}
}
The user implements the initialization function init()
, which will automatically execute the init()
function at the beginning of the strategy to complete the initialization task.
function main(){
Log("The first line of code is executed!", "#FF0000")
Log("Exit!")
}
// Initialization Function
function init(){
Log("Initialization!")
}
def main():
Log("The first line of code is executed!", "#FF0000")
Log("Exit!")
def init():
Log("Initialization!")
void main() {
Log("The first line of code is executed!", "#FF0000");
Log("Exit!");
}
void init() {
Log("Initialization!");
}
When an exception occurs, onerror()
function execution is triggered.
This function does not support Python writing strategy.
function main() {
var arr = []
Log(arr[6].Close)
}
function onerror() {
Log("error")
}
# python does not support
// C++ does not support
In strategies written in JavaScript, Python, C++ languages, the Sleep() function needs to be called in the main loop of the strategy, it will be used to control backtesting time series backtracking speed. In the real market, it is used to control the strategy polling interval, and also control the frequency of accessing the API interface of the exchange. Because the strategy for commodity futures is event-driven (the market data is pushed by the exchange), the strategy for commodity futures can be written without the Sleep()
function.
Example of basic framework of cryptocurrency strategies:
function onTick(){
// Write strategy logic here, it will be called constantly, such as printing market information.
Log(exchange.GetTicker())
}
function main(){
while(true){
onTick()
// Sleep function is mainly used to control the polling frequency of cryptocurrency strategies to prevent access to the exchange API interface 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);
}
}
For 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 1 second, I can write:
function onTick(){
exchange.Buy(100, 1)
}
function main(){
while(true){
onTick()
// The pause period can be customized in milliseconds (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);
}
}
Classic Commodity Futures Strategies Structure:
function main(){
while(true){
// Only when the exchange.IO("status") function returns true, that is, is it true, can the market, transaction and other functions be called
if(exchange.IO("status")){
exchange.SetContractType("MA000")
var ticker = exchange.GetTicker()
Log("MA000 ticker:", ticker)
LogStatus(_D(), "CTP is connected!")
} else {
LogStatus(_D(), "CTP is not connected!")
}
}
}
def main():
while True:
if exchange.IO("status"):
exchange.SetContractType("MA000")
ticker = exchange.GetTicker()
Log("MA000 ticker:", ticker)
LogStatus(_D(), "CTP is connected!")
else:
LogStatus(_D(), "CTP is not connected!")
void main() {
while(true) {
if(exchange.IO("status") == 1) {
exchange.SetContractType("MA000");
auto ticker = exchange.GetTicker();
Log("MA000 ticker:", ticker);
LogStatus(_D(), "CTP is connected!");
} else {
LogStatus(_D(), "CTP is not connected!");
}
}
}
Template Class Library
is a reusable code module in the FMZ Quant trading platform, and is a category of trading strategy code. When creating a trading strategy, if the category is set to Template Class Library
, a template class library is created in the strategy library account that currently logged in the FMZ Quant trading platform. Once created, it is no longer possible to modify the category to a normal strategy.
Export function of template class library The exported function is an interface function of the template class library, and can be called by a strategy that references the template class library. The exported function is declared and implemented in the template class library as follows:
/*
-- This method is called directly with $.Test() after the strategy references the template.
-- main function will not triggered in the strategy, 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 this template and calls this method directly with ext::Test()
void Test() {
Log("template call");
}
Parameters of the template class library The template class library can also set its own interface parameters. The parameters of the template class library are used in the form of global variables in the template class library code.
Template class library setting parameters:
Template class library code:
$.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;
}
The strategy code that quote the Template Class Library
example 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());
}
Reference the template class library
After click the reference option, save the strategy.
It can be regarded as an exchange object. By default, it is the first exchange added in the strategy parameters. All data interaction with the exchange is realized through the functions in this object.
Backtesting adding exchange objects
Add exchange object on real market robot page
The added exchange object corresponds to the exchange
object in the code:
function main() {
Log("The name of the first exchange object added on the real market robot page or backtest page:", exchange.GetName(), "label:", exchange.GetLabel())
}
def main():
Log("The name of the first exchange object added on the real market robot page or backtest page:", exchange.GetName(), "label:", exchange.GetLabel())
void main() {
Log("The name of the first exchange object added on the real market robot page or backtest page:", exchange.GetName(), "label:", exchange.GetLabel());
}
An array of exchange
, which contains multiple exchange objects, exchanges[0]
means exchange
.
The added exchange objects correspond to exchanges[0]
, exchanges[1]
, exchanges[2]
… in the strategy code, and so on.
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());
}
}
Status
attribute in the Order
structure.
Constant Name | Definition | Value |
---|---|---|
ORDER_STATE_PENDING | unfinished | 0 |
ORDER_STATE_CLOSED | finished | 1 |
ORDER_STATE_CANCELED | already cancelled | 2 |
ORDER_STATE_UNKNOWN | Unknown state (other states) | 3 |
ORDER_STATE_UNKNOWN status, you can call exchange.GetRawJSON()
to get the original order status information, query the exchange document, and see the detailed description.
Type
attribute in the Order
structure.
Constant Name | Definition | Value |
---|---|---|
ORDER_TYPE_BUY | Buying Order | 0 |
ORDER_TYPE_SELL | Selling Order | 1 |
Type
attribute in the Position
structure.
Constant Name | Definition | Description | Applicable | Value |
---|---|---|---|---|
PD_LONG | Long positions | CTP uses exchange.SetDirection(“closebuy_today”) to set the closing position direction, and cryptocurrency futures use exchange.SetDirection(“closebuy”) to set the closing position direction | Commodity Futures, cryptocurrency Futures | 0 |
PD_SHORT | Short positions | CTP uses exchange.SetDirection(“closesell_today”) to set the closing position direction, and cryptocurrency futures use exchange.SetDirection(“closesell”) to set the closing position direction | Commodity Futures, cryptocurrency Futures | 1 |
PD_LONG_YD | Long positions yesterday | CTP uses exchange.SetDirection(“closebuy”) to set the closing position direction | Commodity Futures | 2 |
PD_SHORT_YD | Short positions yesterday | CTP uses exchange.SetDirection(“closesell”) to set the closing position direction | Commodity Futures | 3 |
Offset
attribute in the Order
structure.
Constant Name | Definition | Value |
---|---|---|
ORDER_OFFSET_OPEN | Opened Position Orders | 0 |
ORDER_OFFSET_CLOSE | Closed Position Orders | 1 |
In the trading strategy code, 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, Python modify the global variables in the strategy need to use the global
keyword.
Parameter Types:
Variable | Description | Remarks | Type | Default Value | Description |
---|---|---|---|---|---|
number | Number type | Remarks | Number (number) | 1 | C ++ strategy is float 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 | Drop-down box | Remarks | Drop-down box(selected) | 1|2|3 | The combox variable itself is a numerical value, which represents the index of the column selected by the drop-down control. Value 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 | Use the same as a string, the encrypted string will be sent encrypted and will not be transmitted in plain text |
number
,string
, combox
,bool
, secretString
.Parameter dependent 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
show and hide based on a parameter: isShowA
(boolean type) true or false.
You need to set the numberA
variable on the interface parameters to: numberA@isShowA
.
In this way, if the isShowA
parameter is not checked, the numberA
parameter is hidden.
Strategy interface parameters, interactive controls, and parameter grouping functions on templates:
Just add (?First group)
at the beginning of the description of the parameter that starts the grouping.
As shown in the figure:
When the strategy is in using, the parameters are displayed in groups:
Parameter default values saving:
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 backtest settings
button after the strategy parameters are modified.
You can save the strategy parameters setting in code form:
/*backtest
start: 2020-02-29 00:00:00
end: 2020-03-29 00:00:00
period: 1d
args: [["number",10],["string","Hello FMZ"],["combox",1],["bool",false]]
*/
'''backtest
start: 2020-02-29 00:00:00
end: 2020-03-29 00:00:00
period: 1d
args: [["number",10],["string","Hello FMZ"],["combox",1],["bool",false]]
'''
/*backtest
start: 2020-02-29 00:00:00
end: 2020-03-29 00:00:00
period: 1d
args: [["number",10],["string","Hello FMZ"],["combox",1],["bool",false]]
*/
Some functions will be accompanied by the original JSON information requested during the call. The original JSON data is stored in the Info attribute of the returned object. Since the backtest is not an interface to access an exchange, it is returned during the backtest that has no Info
attribute in the data. The following is a description of the main attributes of each data structure.
Get all transaction history (not itself), returned by exchange.GetTrades()
function.
{
Time : 1567736576000, // Time (Unix timestamp milliseconds)
Price : 1000, // Price
Amount : 1, // Quantity
Type : 0 // Order type, refer to the order type in the constant, 0 is ORDER_TYPE_BUY, ORDER_TYPE_BUY is 0
}
Market quotes are returned by the exchange.GetTicker()
function.
{
Info : {...}, // After requesting the exchange interface, the original data of the exchange interface response, this attribute is not available during the backtest
High : 1000, // highest price
Low : 500, // lowest price
Sell : 900, // Selling price 1
Buy : 899, // Buying price 1
Last : 900, // Last traded price
Volume : 10000000, // Recent trading volume
Time : 1567736576000 // Millisecond-level timestamp
}
The standard OHLC structure is used to draw K-line and indicator analysis. The exchange.GetRecords()
function returns this structure array.
{
Time : 1567736576000, // A timestamp, accurate to the millisecond, the same format as the result obtained by Javascript's newDate().GetTime()
Open : 1000, // opening price
High : 1500, // highest price
Low : 900, // lowest price
Close : 1200, // closing price
Volume : 1000000 // Trading volume
}
Order structure, returned by exchange.GetOrder()
, exchange.GetOrders()
function.
{
Info : {...}, // After requesting the exchange interface, the original data of the exchange interface response, this attribute is not available during the backtest
Id : 123456, // Transaction Unique ID
Price : 1000, // Placing Order Price
Amount : 10, // Placing Order Quantity
DealAmount : 10, // Executed Volume
AvgPrice : 1000, // The average transaction price, note that some exchanges do not provide this data(the setting is 0)
Status : 1, // Order status, refer to the order status in the constant ORDER_STATE_CLOSED
Type : 0, // Order type, refer to the order type ORDER_TYPE_BUY in the constant
Offset : 0 // In the order data of cryptocurrency futures and commodity futures, the order opening and closing direction, ORDER_OFFSET_OPEN is the opening position, ORDER_OFFSET_CLOSE is the closing direction
ContractType : "" // This attribute is "" for spot orders, and specific contract codes for futures orders
}
Depth of market order, that is, exchange.GetDepth()
returns the data structure of the elements in the Bids and Asks arrays in the data.
{
Price : 1000, // Price
Amount : 1 // Quantity
}
The market depth is returned by the exchange.GetDepth()
function.
{
Asks : [...], // Array of selling orders, array of MarketOrder, sorted by price from low to high
Bids : [...], // Array of selling orders, array of MarketOrder, sorted by price from high to low
Time : 1567736576000 // Millisecond-level timestamp
}
Account information, returned by the exchange.GetAccount()
function.
{
Info : {...}, // After requesting the exchange interface, the original data of the exchange interface response, this attribute is not available during the backtest
Balance : 1000, // Balance (RMB or USD, on Poloniex exchanges such as ETC_BTC, Balance refers to the amount of BTC, Stocks refers to the amount of ETC)
FrozenBalance : 0, // Frozen balance
Stocks : 1, // The number of BTC/LTC, the cryptocurrency spot is the balance of the current operable currency (minus the frozen currency), and the cryptocurrency futures are the contract's currently available margin (traditional commodity futures do not have this attribute)
FrozenStocks : 0 // Number of BTC/LTC frozen (traditional commodity futures do not have this attribute)
}
For information about positions held in futures trading, this structure array is returned by the exchange.GetPosition()
function.
{
Info : {...}, // After requesting the exchange interface, the original data of the exchange interface response, this attribute is not available during the backtest
MarginLevel : 10, // Leverage Size
Amount : 100, // holding position volume, OKEX contract exchange, indicates the number of contracts (integer and greater than 1, the number of contracts)
FrozenAmount : 0, // Position freeze
Price : 10000, // Average position price
Profit : 0, // Position floating profit and loss (data currency unit: BTC/LTC, traditional futures unit: RMB, stocks do not support this field, Note: The OKEX contract refers to the realization of surplus in the case of a full position, not the holding position profit and loss, and the position by position refers to the holding position profit and loss)
Type : 0, // PD_LONG is a long position (closed with closebuy_today in CTP), PD_SHORT is a short position (closed with closesell_today in CTP), (in CTP futures) PD_LONG_YD is a yesterday long position (closed with closebuy), PD_SHORT_YD is a yesterday short position (closed with closesell)
ContractType : "quarter", // Commodity futures are contract codes, stocks are 'Exchange code_Stock code', the specific parameter SetContractType's incoming type
Margin : 1 // Margin occupied by positions
}
Version()
, Returns the current version number of the system, a string value, such as 3.0. Return value: string type.
Sleep(Millisecond)
sleep function makes the program pause for a period of time. Parameter value: Millisecond is of type number.
The parameter unit is in milliseconds, for example: Sleep(1000)
is sleep for one second.
Note:
When writing strategies using the Python
language, the Sleep(Millisecond)
function should be used for operations that wait for a time such as the polling interval. It is not recommended to use the time library function time.time(second)
in Python.
Because after using the time.time(second)
function in the strategy, the strategy program will actually wait for a certain number of seconds (the number of seconds in the second
parameter setting), it will make the backtest progress very slow.
IsVirtual()
, to determine whether it is a simulated backtest. Return value: bool type.
The simulated backtest status returns true, and the real market returns false.
Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)
, send mail function.
Parameter value: all are of type string. Return value: bool type, true is returned after successful transmission.
smtpServer is the sending mailbox smtp, smtpUsername is the mailbox account, smtpPassword is the mailbox password, mailTo is the acceptance mailbox account, title is the title, body is the content. E.g:
function main(){
Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
}
def main():
Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
void main() {
Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
Note: Alibaba Cloud server may block some ports, so that the mail cannot be sent out. If you need to change the port, you can directly add the port number in the first parameter: For example: qq’s smtp.qq.com:587, the port test is available.
If an error occurs: unencrypted connection, you need to modify the Mail
function smtpServer
parameter to: format ssl://xxxxx.com:xxx
, for example, the SMTP ssl method of QQ mailbox: ssl://smtp.qq.com:465
or: format smtp://xxxxx.com:xxx
.
SetErrorFilter(RegEx)
, error message filtering. Parameter value: string type.
Errors matched by this regular expression will not be uploaded to the log system, and can be called multiple times (filtered logs are not written to the database file of the corresponding robot ID in logs/robot in the docker directory, to prevent frequent error reporting Cause the database file to expand)
function main() {
SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
}
def main():
SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
`