Depois de ter concluído o projeto de uma estratégia de negociação quantitativa, como você pode saber a situação básica de sua estratégia, como a lógica da estratégia e a direção dos retornos da estratégia?
A Plataforma de Negociação Quant FMZ divide o sistema de backtest emnível de boteNível de simulação. O nível de bot é para backtest completamente de acordo com os dados históricos completos; enquanto o nível de simulação backtest geratick
O backtesting é um tipo de backtesting que consiste em testar os dados de acordo com os dados reais da linha K em intervalos regulares para backtest. Ambos são baseados nos dados históricos reais, mas os dados do nível do bot são mais precisos e os resultados são mais credíveis. No entanto, o backtesting é apenas o desempenho da estratégia de acordo com os dados históricos. Os dados históricos não podem representar completamente o mercado futuro. O mercado histórico pode se repetir, ou também pode levar ao Cisne Negro. Portanto, os resultados do backtest devem ser tratados racionalmente e objetivamente.
ONível de simulaçãoGerar o valor simuladodados de carrapatosbaseado no período de linha K subjacente, cada período de linha K subjacente irá gerar um máximo de 12 pontos de tempo de backtest;Nível de mercado realO backtesting usa dados reais coletados segundo a segundo, o volume de dados é muito grande e a velocidade de backtesting é lenta, por isso não pode ser backtestado por um período muito longo de tempo.
Descrição do mecanismo do sistema de backtesting
Tick de nível de simulação ONível de simulaçãobaseia-se nos dados de linha K subjacentes do sistema de backtest, simulando os dados de tick para backtest dentro do quadro dos valores de preço mais alto, preço mais baixo, preço de abertura e preço de fechamento de uma determinada barra de linha K subjacente de acordo com um determinado algoritmo. Como dados de tick em tempo real na série de tempo de backtesting, ele retorna quando o programa de estratégia chama a interface. Para mais detalhes, consulte:Descrição do mecanismo de nível de simulação do sistema de backtesting.
Tick de nível de bot
O backtest de nível de bot é os dados reais de nível de tick na série de tempo Bar. Para estratégias baseadas em dados de nível de tick, usar o nível de mercado real para backtest é mais próximo da realidade. No backtest de nível de bot, os dados de tick são dados registrados reais, não simulados. Ele suporta dados de profundidade, reprodução de dados de registro de negociações de mercado, profundidade personalizada e cada dado de negociação individual. O tamanho máximo do backtest de dados de nível de mercado real é de até um máximo de 50MB, sem limite no intervalo de tempo do backtest dentro do limite superior do conjunto de dados.GetDepth
, GetTrades
No momento em que os dados do mercado estão na linha do tempo, chamandoGetTicker
, GetTrades
, GetDepth
eGetRecords
O tempo do backtest não será movido várias vezes quando o tempo se move na linha do tempo do backtest (o que não desencadeará um salto para o próximo momento de dados do mercado). As chamadas repetidas para uma das funções acima empurrarão o tempo do backtest para se mover na linha do tempo do backtest (salto para o próximo momento de dados do mercado). Quando o nível real do mercado é usado para backtest, não é recomendado escolher um tempo anterior. Pode não haver dados de nível real do mercado no período de tempo prematuro.
Tick de nível de boteTick de nível de simulaçãoO mecanismo de correspondência de transacções do sistema de backtest: a correspondência de transacções de ordens é realizada de acordo com o preço visto e o volume total é negociado.
O sistema de backtesting suporta estratégias de backtesting escritas e concebidas por:JavaScript
, TypeScript
, Python
, C++
, PINE
, MyLanguage
, Blockly
Visualização.
O backtest deJavaScripteC++estratégias de negociação é conduzida no navegador, e o robô de mercado real ouWexAppEmpréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimos empréstimosWexAppemulado de câmbio da plataforma FMZ Quant Trading) é executado sem instalar qualquer outro software, bibliotecas ou módulos.
O backtest dePythonA operação de mercado real e o backtest dependem ambos do sistema de avaliação de mercado.PythonSe algumas bibliotecas forem necessárias, elas precisam ser instaladas manualmente (apenas o docker comumPythonAs bibliotecas são suportadas nos servidores públicos FMZ Quant).
SuportaJavaScriptestratégia de depuração de backtesting no Chrome DevTools,Por favor, consulte:.
A função de otimização de parâmetros do sistema de backtest da FMZ Quant Trading Platform é definir as combinações de parâmetros de acordo com cada opção de otimização de parâmetros durante o backtesting.Optimizaçãoopção no lado direito do parâmetro estratégia para exibir as configurações de otimização.
JavaScript
, PINE
, eMy Language
, e não suporta a otimização de parâmetros em modelos.As combinações de parâmetros são geradas com base nominimum
, maximum
, estep size
O sistema de backtesting itera através destas combinações de parâmetros para backtesting (ou seja, backtesting cada combinação de parâmetros uma vez).NúmeroO sistema de backtesting pode ser otimizado.
Empágina de edição de estratégia, na paginação de
backtest
(salvos no código da estratégia através do botão backtest
na área de edição de estratégias./*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
'''backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
'''
/*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
Clique em JavaScript
/Python
/C++
/MyLanguage
/PINE
linguagens ao guardar as definições de backtest no código de estratégia:
MyLanguage:
(*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*)
Língua PINE:
/*backtest
start: 2021-06-26 00:00:00
end: 2021-09-23 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
O sistema de backtesting da FMZ Quant Trading Platform suporta fontes de dados personalizadas, o sistema de backtesting utiliza oGET
método para solicitar uma URL personalizada (URL acessível ao público) para obter uma fonte de dados externa para backtest. Os parâmetros de solicitação adicionais são os seguintes:
Parâmetro | Significado | Explicação |
---|---|---|
símbolo | Nome do símbolo | Dados do mercado à vista, tais como:BTC_USDT , dados do mercado de futuros, tais como:BTC_USDT.swap , dados da taxa de financiamento de contratos perpétuos de futuros, tais como:BTC_USDT.funding , dados do índice de preços de contratos futuros perpétuos, tais como:BTC_USDT.index |
eid | Intercâmbio | Os valores da posição em risco são os valores da posição em risco, incluindo os valores da posição em risco. |
redondo | Exatidão dos dados | True significa que a precisão específica é definida nos dados fornecidos pela fonte de dados personalizada.round=true |
período | Período de dados de linha K (milissegundos) | tais como:60000 é um período de 1 minuto |
profundidade | Níveis de profundidade | 1-20 |
negócios | Se os dados precisam ser divididos | Verdadeiro (1) / Falso (2) |
de | Horário de início | carimbo de tempo unix |
para | Tempo do Fim | carimbo de tempo unix |
detalhe | Dados solicitados para os detalhes do símbolo | O pedido enviado pelo FMZ Quant Trading Platform Backtesting System para a fonte de dados personalizada é fixado como:detail=true |
costume | – | Este parâmetro pode ser ignorado |
Quando a fonte de dados dos objetos de câmbio spot e de câmbio de futuros for definida como uma fonte de dados personalizada (feeder), o sistema de backtesting envia um pedido ao serviço de fonte de dados personalizada:
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Bitget&from=1351641600&period=86400000&round=true&symbol=BTC_USDT&to=1611244800&trades=1
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_OKX&from=1351641600&period=86400000&round=true&symbol=BTC_USDT.swap&to=1611244800&trades=1
O formato devolvido deve ser um dos dois seguintes formatos (que serão reconhecidos automaticamente pelo sistema):
Nível de simulação Tick, o seguinte é um exemplo de dados JSON:
{
"detail": {
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10
},
"schema":["time", "open", "high", "low", "close", "vol"],
"data":[
[1564315200000, 9531300, 9531300, 9497060, 9497060, 787],
[1564316100000, 9495160, 9495160, 9474260, 9489460, 338]
]
}
Marque o nível do bot, o seguinte é um exemplo de dados JSON:
Os dados de backtest de nível Tick (contém informações sobre a profundidade do mercado, e o formato de profundidade é uma matriz de[price, volume]
Pode ter vários níveis de profundidade,asks
para a ordem ascendente de preços,bids
para ordem decrescente de preços).
{
"detail": {
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10
},
"schema":["time", "asks", "bids", "trades", "close", "vol"],
"data":[
[1564315200000, [[9531300, 10]], [[9531300, 10]], [[1564315200000, 0, 9531300, 10]], 9497060, 787],
[1564316100000, [[9531300, 10]], [[9531300, 10]], [[1564316100000, 0, 9531300, 10]], 9497060, 787]
]
}
Campo | Descrição |
---|---|
detalhe | Informações pormenorizadas sobre o tipo de dados solicitado, |
Incluindo o nome da moeda denominada, o nome da A moeda de negociação, a precisão, a quantidade mínima de encomenda, etc. Especifica os atributos das colunas nos dados matriz, que é sensível a minúsculas e é limitada apenas ao tempo, aberta, alto, baixo, fechado, vol, pede, oferece, negociações dados. A estrutura da coluna, dados gravados de acordo com o esquema Configurações.
campo de detalhes
Campo | Descrição |
---|---|
eid | Exchange Id, por favor, note que o local e futuros de um |
Certas trocas têm diferentes eids. | |
símbolo | Código do produto de negociação |
alias | O símbolo no intercâmbio correspondente ao corrente |
Código do produto comercial | |
baseMudança | Moeda de negociação |
CitaçãoMoeda | Moeda denominada |
MargemCurrency | Moeda de margem |
BasePrecisione | Precisão da moeda da transacção |
CitaçãoPrecisione | Preço da moeda exacta |
MinQty | Quantidade mínima de encomenda |
MaxQty | Quantidade máxima de encomenda |
Min Nocional | Montante mínimo da encomenda |
Max Nocional | Montante máximo da encomenda |
preçoTick | Salto de preços |
volumeMarque | Valor mínimo de alteração da quantidade de encomenda (um salto |
quantidade da encomenda) | |
Margem Nível | Valor de alavancagem de futuros |
Contrato Tipo | Para contratos perpétuos definidos para:swap , o |
sistema backtest continuará a enviar taxa de financiamento e índice de preços pedidos.
Atributos especiais de colunaasks
, bids
, trades
:
Campo | Descrição | Observações |
---|---|---|
pedidos / propostas | [preço, volume],...] | Por exemplo, os dados |
OLive Trading Level Tick
Exemplo de dados:[[9531300, 10]]
- Sim, sim.
O tempo, a direcção, o preço, o volume,...
Por exemplo, os dados noLive Trading Level Tick
Exemplo de dados:[[1564315200000, 0, 9531300, 10]]
|
Ao fazer backtesting de contratos perpétuos nas bolsas de futuros, custom
As fontes de dados também exigem dados adicionais sobre taxas de financiamento e preços
O sistema de backtesting continuará a enviar solicitações
para as taxas de financiamento apenas quando os dados de mercado solicitados são devolvidos
e o campo de detalhes na estrutura devolvida contém o"contractType": "swap"
Pares chave-valor.
Quando o sistema de backtesting recebe dados da taxa de financiamento, ele irá Continuar a enviar pedidos de dados do índice de preços.
A estrutura dos dados da taxa de financiamento é a seguinte:
{
"detail": {
"eid": "Futures_Binance",
"symbol": "BTC_USDT.funding",
"alias": "BTC_USDT.funding",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "",
"basePrecision": 8,
"quotePrecision": 8,
"minQty": 1,
"maxQty": 10000,
"minNotional": 1,
"maxNotional": 100000000,
"priceTick": 1e-8,
"volumeTick": 1e-8,
"marginLevel": 10
},
"schema": [
"time",
"open",
"high",
"low",
"close",
"vol"
],
"data": [
[
1584921600000,
-16795,
-16795,
-16795,
-16795,
0
],
[
1584950400000,
-16294,
-16294,
-16294,
-16294,
0
]
// ...
]
}
Exemplo de pedido de dados de taxa de financiamento a partir do backtesting O sistema é:
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_Binance&from=1351641600&period=86400000&round=true&symbol=BTC_USDT.funding&to=1611244800&trades=0
A estrutura dos dados do índice de preços é a seguinte:
{
"detail": {
"eid": "Futures_Binance",
"symbol": "BTC_USDT.index",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"contractType": "index",
"marginCurrency": "USDT",
"basePrecision": 3,
"quotePrecision": 1,
"minQty": 0.001,
"maxQty": 1000,
"minNotional": 0,
"maxNotional": 1.7976931348623157e+308,
"priceTick": 0.1,
"volumeTick": 0.001,
"marginLevel": 10,
"volumeMultiple": 1
},
"schema": [
"time",
"open",
"high",
"low",
"close",
"vol"
],
"data": [
[1584921600000, 58172, 59167, 56902, 58962, 0],
[1584922500000, 58975, 59428, 58581, 59154, 0],
// ...
]
}
Exemplo de pedido de dados do índice de preços enviado pelo backtesting O sistema é:
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_Binance&from=1351641600&period=86400000&round=true&symbol=BTC_USDT.index&to=1611244800&trades=0
Especificar o endereço da fonte de dados, por exemplo:http://120.24.2.20:9090/data
O programa de serviço de fonte de dados personalizado é escrito usandoGolang
:
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
// request: GET http://xxx.xx.x.xx:9090/data?custom=0&depth=20&detail=true&eid=OKX&from=1584921600&period=86400000&round=true&symbol=BTC_USDT&to=1611244800&trades=1
// http://xxx.xx.x.xx:9090/data?custom=0&depth=20&detail=true&eid=Futures_Binance&from=1599958800&period=3600000&round=true&symbol=BTC_USDT.swap&to=1611244800&trades=0
fmt.Println("request:", r)
// response
defer func() {
// response data
/* e.g. data
{
"detail": {
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10
},
"schema": [
"time",
"open",
"high",
"low",
"close",
"vol"
],
"data": [
[1610755200000, 3673743, 3795000, 3535780, 3599498, 8634843151],
[1610841600000, 3599498, 3685250, 3385000, 3582861, 8015772738],
[1610928000000, 3582499, 3746983, 3480000, 3663127, 7069811875],
[1611014400000, 3662246, 3785000, 3584406, 3589149, 7961130777],
[1611100800000, 3590194, 3641531, 3340000, 3546823, 8936842292],
[1611187200000, 3546823, 3560000, 3007100, 3085013, 13500407666],
[1611273600000, 3085199, 3382653, 2885000, 3294517, 14297168405],
[1611360000000, 3295000, 3345600, 3139016, 3207800, 6459528768],
[1611446400000, 3207800, 3307100, 3090000, 3225990, 5797803797],
[1611532800000, 3225945, 3487500, 3191000, 3225420, 8849922692]
]
}
*/
// /* Simulation level Tick
ret := map[string]interface{}{
"detail": map[string]interface{}{
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10,
},
"schema": []string{"time","open","high","low","close","vol"},
"data": []interface{}{
[]int64{1610755200000, 3673743, 3795000, 3535780, 3599498, 8634843151}, // 1610755200000 : 2021-01-16 08:00:00
[]int64{1610841600000, 3599498, 3685250, 3385000, 3582861, 8015772738}, // 1610841600000 : 2021-01-17 08:00:00
[]int64{1610928000000, 3582499, 3746983, 3480000, 3663127, 7069811875},
[]int64{1611014400000, 3662246, 3785000, 3584406, 3589149, 7961130777},
[]int64{1611100800000, 3590194, 3641531, 3340000, 3546823, 8936842292},
[]int64{1611187200000, 3546823, 3560000, 3007100, 3085013, 13500407666},
[]int64{1611273600000, 3085199, 3382653, 2885000, 3294517, 14297168405},
[]int64{1611360000000, 3295000, 3345600, 3139016, 3207800, 6459528768},
[]int64{1611446400000, 3207800, 3307100, 3090000, 3225990, 5797803797},
[]int64{1611532800000, 3225945, 3487500, 3191000, 3225420, 8849922692},
},
}
// */
/* Bot level Tick
ret := map[string]interface{}{
"detail": map[string]interface{}{
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10,
},
"schema": []string{"time", "asks", "bids", "trades", "close", "vol"},
"data": []interface{}{
[]interface{}{1610755200000, []interface{}{[]int64{9531300, 10}}, []interface{}{[]int64{9531300, 10}}, []interface{}{[]int64{1610755200000, 0, 9531300, 10}}, 9497060, 787},
[]interface{}{1610841600000, []interface{}{[]int64{9531300, 15}}, []interface{}{[]int64{9531300, 15}}, []interface{}{[]int64{1610841600000, 0, 9531300, 11}}, 9497061, 789},
},
}
*/
b, _ := json.Marshal(ret)
w.Write(b)
}()
}
func main () {
fmt.Println("listen http://localhost:9090")
http.HandleFunc("/data", Handle)
http.ListenAndServe(":9090", nil)
}
Estratégia de ensaio,JavaScript
Exemplo:
/*backtest
start: 2021-01-16 08:00:00
end: 2021-01-22 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"OKX","currency":"BTC_USDT","feeder":"http://120.24.2.20:9090/data"}]
args: [["number",2]]
*/
function main() {
var ticker = exchange.GetTicker()
var records = exchange.GetRecords()
Log(exchange.GetName(), exchange.GetCurrency())
Log(ticker)
Log(records)
}
FMZ Quant Trading Platform tem código aberto para oJavaScript
linguagem e aPython
linguagem do motor de backtest local, suportando a definição do período de linha K subjacente durante o backtesting.
Tabela de atalho para alternar entre a página de estratégia Ctrl +,
para mudar de volta para a página Ctrl
Aperta a tecla.,
.
Chave de atalho para estratégia de poupança
Usa a chave.Ctrl + s
para salvar estratégias.
atalho para iniciar estratégia backtest
Usa a chave.Ctrl + b
para permitir o
O código fonte do algoritmo Sharpe no sistema de backtesting:
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays) {
// force by days
period = 86400000
if (profits.length == 0) {
return null
}
var freeProfit = 0.03 // 0.04
var yearRange = yearDays * 86400000
var totalReturns = profits[profits.length - 1][1] / totalAssets
var annualizedReturns = (totalReturns * yearRange) / (te - ts)
// MaxDrawDown
var maxDrawdown = 0
var maxAssets = totalAssets
var maxAssetsTime = 0
var maxDrawdownTime = 0
var maxDrawdownStartTime = 0
var winningRate = 0
var winningResult = 0
for (var i = 0; i < profits.length; i++) {
if (i == 0) {
if (profits[i][1] > 0) {
winningResult++
}
} else {
if (profits[i][1] > profits[i - 1][1]) {
winningResult++
}
}
if ((profits[i][1] + totalAssets) > maxAssets) {
maxAssets = profits[i][1] + totalAssets
maxAssetsTime = profits[i][0]
}
if (maxAssets > 0) {
var drawDown = 1 - (profits[i][1] + totalAssets) / maxAssets
if (drawDown > maxDrawdown) {
maxDrawdown = drawDown
maxDrawdownTime = profits[i][0]
maxDrawdownStartTime = maxAssetsTime
}
}
}
if (profits.length > 0) {
winningRate = winningResult / profits.length
}
// trim profits
var i = 0
var datas = []
var sum = 0
var preProfit = 0
var perRatio = 0
var rangeEnd = te
if ((te - ts) % period > 0) {
rangeEnd = (parseInt(te / period) + 1) * period
}
for (var n = ts; n < rangeEnd; n += period) {
var dayProfit = 0.0
var cut = n + period
while (i < profits.length && profits[i][0] < cut) {
dayProfit += (profits[i][1] - preProfit)
preProfit = profits[i][1]
i++
}
perRatio = ((dayProfit / totalAssets) * yearRange) / period
sum += perRatio
datas.push(perRatio)
}
var sharpeRatio = 0
var volatility = 0
if (datas.length > 0) {
var avg = sum / datas.length;
var std = 0;
for (i = 0; i < datas.length; i++) {
std += Math.pow(datas[i] - avg, 2);
}
volatility = Math.sqrt(std / datas.length);
if (volatility !== 0) {
sharpeRatio = (annualizedReturns - freeProfit) / volatility
}
}
return {
totalAssets: totalAssets,
yearDays: yearDays,
totalReturns: totalReturns,
annualizedReturns: annualizedReturns,
sharpeRatio: sharpeRatio,
volatility: volatility,
maxDrawdown: maxDrawdown,
maxDrawdownTime: maxDrawdownTime,
maxAssetsTime: maxAssetsTime,
maxDrawdownStartTime: maxDrawdownStartTime,
winningRate: winningRate
}
}
Editor de Estratégia
Funções de entrada de estratégia