[TOC] Este tutorial contém conhecimentos básicos de escrita de estratégia, incluindo introdução de API, backtest, gráficos e muito mais. Depois de aprender este tutorial básico, os usuários serão capazes de usar a API básica proficientemente e escrever uma estratégia de bot estável. Antes de aprender o tutorial, você precisa aprender a usarComece a plataforma FMZ Quant.
Tutorial da versão antiga:FMZ Quant (FMZ.COM) Manual de Escrita de Estratégia 2.0 (Tutorial)Há muitos índices de postagens no tutorial, que são recomendados para ler.
O programa de negociação é o uso de programas para se conectar com plataformas através de API para alcançar a compra e venda automática ou outras funções de acordo com a intenção do projeto.
Atualmente, existem dois protocolos principais de interface para plataformas de criptomoedas: REST e Websocket. Cada vez que o protocolo REST obtém dados, ele precisa ser acessado uma vez. Vamos tomar a API da plataforma simulada
{"data:{"buy":"11351.73","high":"11595.77","last":"11351.85","low":"11118.45","open":"11358.74","quoteVol":"95995607137.00903936","sell":"11356.02","time":1565593489318,"vol":"3552.5153"}}
Desta forma, você pode ver que a negociação seguindo as últimas cotações de mercado do par de negociação BTC_USDT, mudará a cada vez que for atualizado;
A plataforma de negociação FMZ Quant encapsula a interface REST de cada plataforma e usa uma maneira unificada de chamar e um formato de dados unificado, tornando a escrita de estratégia mais simples e mais geral.
A maioria das partes do documento da API da plataforma FMZ usa JavaScript como exemplo, mas devido à encapsulamento, quase não há diferença entre as diferentes linguagens, e você só precisa prestar atenção em questões de sintaxe.
Como o Python tem versões diferentes, ele pode ser especificado no início do programa, como:#!Python2
e#!Python3
. Observe que o JavaScript recentemente atualizou sua sintaxe ES6, e aqueles que estão interessados podem aprender sobre isso. Os códigos Python e Javascript com as mesmas funções são mostrados abaixo. Pode-se ver que há apenas diferenças de sintaxe, então o documento da API só dá exemplos de Javascript, e este tutorial também levará em conta os casos de uso especiais do Python.
#python code
def main():
while True:
Log(exchange.GetAccount().Balance)
Sleep(2000)
#the corresponding Js code
function main(){
while(true){
Log(exchange.GetAccount().Balance)
Sleep(2000)
}
}
A plataforma FMZ Quant fornece o
O programa de estratégia é o mesmo que um programa normal, que é executado em ordens de código. A parte especial é que deve haver uma função
Outras funções com acções especiais são apresentadas da seguinte forma:
function onTick(){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
//write the strategy logic here, and it will be called ever 6 seconds
}
function main(){
while(true){
onTick()
Sleep(6000)
}
}
No exemplo anterior, se houver um erro no acesso à rede, a estratégia pode parar diretamente. Se você quiser uma estratégia semelhante ao reinicio automático e não parar, você pode usar o loop principal
function onTick(){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
//write the strategy logic here, and it will be called ever 6 seconds
}
function main(){
try{
while(true){
onTick()
Sleep(6000)
}
}catch(err){
Log(err)
}
}
Ao chamar qualquer API relacionada à plataforma, você precisa especificar a plataforma e o par de negociação.exchange
Por exemplo, o queexchange.GetTicker()
O preço de mercado para este par de câmbio é o ticker do mercado.
A plataforma FMZ Quant suporta a adição de múltiplos objetos exchanges
matriz para representá-los, ou sejaexchanges[0]
eexchanges[1]
... e assim por diante, de acordo com a ordem de adição quando o bot é criado.BTC_USDT
, o antigo
Obviamente, se operarmos muitos pares de negociação, este método será muito inconveniente.exchange.SetCurrency("BTC_USDT")
; em seguida, o par de negociação vinculado aexchange
torna-seBTC_USDT
, que permanecerá válido até à próxima chamada para alterar o par de negociação.Observe que o backtest suporta trocar pares comerciais recentementeAbaixo está um exemplo específico:
var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT"]
var buyValue = 1000
function main(){
for(var i=0;i<symbols.length;i++){
exchange.SetCurrency(symbols[i])
var ticker = exchange.GetTicker()
var amount = _N(buyValue/ticker.Sell, 3)
exchange.Buy(ticker.Sell, amount)
Sleep(1000)
}
}
Como mencionado no exemplo anterior, a interface de mercado é geralmente uma interface pública, que pode ser acessada por todos. As interfaces de mercado comuns são: GetTicker, GetDepth, GetRecords e GetTrades. A cotação de mercado é a base para a estratégia para fazer julgamentos de negociação. Mais tarde, vou apresentá-los um por um. É melhor experimentá-los na
Cada interface tem geralmente umaInfo
campo, que representa a cadeia de dados original devolvida pela plataforma, e que pode ser usada para complementar informações adicionais.JSON.parse()
, enquanto Python usa biblioteca json.Time
O campo indica o carimbo horário da solicitação, que pode ser utilizado para julgar o atraso.
quando se usa qualquer API no bot, o acesso pode falhar e retornarnull
, e Python retornaNone
Neste momento, os dados em uso irão relatar um erro e fazer com que o bot pare, então a tolerância a falhas é muito importante.
GetTicker é provavelmente a interface mais usada. Você pode encontrar o preço executado pela última vez, preço buy1 e preço sell1, e o volume de negociação mais recente. Antes de colocar uma ordem, o preço executado pode ser determinado de acordo com as informações do ticker.{"Info:{}, "High":5226.69, "Low":5086.37,"Sell":5210.63, "Buy":5208.5, "Last":5208.51, "Volume":1703.1245, "OpenInterest":0, "Time":1554884195976}
.
function main() {
var ticker = exchange.GetTicker()
Log(ticker) //return ticker in the debugging tool, and you can see the specific result
Log('Last time executed price:',ticker.Last, 'Buy1 price:', ticker.Buy)
}
GetDepth para obter as informações de profundidade das ordens pendentes. Embora o GetTicker inclua preços de compra 1 e venda 1, se você quiser consultar ordens pendentes mais profundas, você pode usar essa interface, para geralmente verificar 200 ordens pendentes. Os preços de choque podem ser calculados usando essa interface. Abaixo está um resultado de retorno real. Entre eles,
{
"Info":null,
"Asks":[
{"Price":5866.38,"Amount":0.068644},
{"Price":5866.39,"Amount":0.263985},
......
]
"Bids":[
{"Price":5865.13,"Amount":0.001898},
{"Price":5865,"Amount":0.085575},
......
],
"Time":1530241857399
}
Exemplo de uso do GetDepth para Asks & Bids:
function main() {
var depth = exchange.GetDepth()
Log('Buy 1 price:', depth.Bids[0].Price, 'Sell 1 price:', depth.Asks[0].Price)
}
GetRecords é uma das interfaces mais usadas, pode retornar informações de preço em um longo período de tempo, que é a base para o cálculo de vários indicadores. Se o período da linha K não for especificado, significa usar o período padrão ao adicionar um bot. O comprimento da linha K não pode ser especificado e continuará a aumentar ao longo do tempo. O número máximo é de 2000, e na primeira chamada o número é de cerca de 200 (plataformas diferentes retornam números diferentes).
exchange.SetMaxBarLen(Len)
Pode definir o número de K-lines adquiridas pela primeira vez (suportado por algumas plataformas) e definir o número máximo de K-lines.Como por exemplo:exchange.SetMaxBarLen(500)
.
GetRecords pode especificar períodos como PERIOD_M1: 1 minuto, PERIOD_M5: 5 minutos, PERIOD_M15: 15 minutos, PERIOD_M30: 30 minutos, PERIOD_H1: 1 hora e PERIOD_D1: 1 dia.exchange.GetRecords(PERIOD_M1)
Após a atualização do último docker, ele suportará períodos de personalização, que apenas passam o segundo número do período como um parâmetro. A personalização de nível de minuto será sintetizada de acordo com a linha K de 1 minuto, a linha K abaixo de 1 minuto será sintetizada através do GetTrades ((), e os futuros de commodities serão sintetizados de acordo com o tick.Observe que também existem outras variáveis maiúsculas completas comoPERIOD_M1
Eles são as variáveis globais padrão do FMZ. Se você estiver interessado, você pode
Exemplo de dados de retorno:
[
{"Time":1526616000000,"Open":7995,"High":8067.65,"Low":7986.6,"Close":8027.22,"Volume":9444676.27669432},
{"Time":1526619600000,"Open":8019.03,"High":8049.99,"Low":7982.78,"Close":8027,"Volume":5354251.80804935},
{"Time":1526623200000,"Open":8027.01,"High":8036.41,"Low":7955.24,"Close":7955.39,"Volume":6659842.42025361},
......
]
Exemplo de linha K iterada:
function main(){
var close = []
var records = exchange.GetRecords(PERIOD_H1)
Log('total bars: ', records.length)
for(var i=0;i<records.length;i++){
close.push(records[i].Close)
}
return close
}
GetTrades obtém os dados de negociação dentro de um determinado intervalo de tempo (não seus próprios dados de negociação), o que não é suportado por algumas plataformas.
Essas interfaces estão relacionadas à conta, por isso não podem ser obtidas diretamente. Para obtê-las, você precisa usar o API-KEY para assinar. Após o processamento automático unificado de fundo da plataforma FMZ, você pode usá-las diretamente.
GetAccount para obter as informações da conta. Como uma das interfaces mais usadas, ela precisa ser chamada antes de fazer um pedido, para evitar um saldo insuficiente.{"Stocks":0.38594816,"FrozenStocks":0,"Balance":542.858308,"FrozenBalance":0,"Info":{}}
Se o par de negociação for um par de negociação, o valor da moeda em que o par de negociação é negociado é o valor da moeda em que o par de negociação é negociado.BTC_USDT
,
Observe que o resultado de retorno é o resultado do par de negociação especificado, e as informações de outras moedas na conta de negociação está no campo
Um bot que imprime constantemente o valor total do par de negociação atual:
function main(){
while(true){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
var price = ticker.Buy
var stocks = account.Stocks + account.FrozenStocks
var balance = account.Balance + account.FrozenBalance
var value = stocks*price + balance
Log('Account value is: ', value)
LogProfit(value)
Sleep(3000)//sleep 3000ms(3s), A loop must has a sleep, or the rate-limit of the exchange will be exceed
//when run in debug tool, add a break here
}
}
Métodos de invocação incluemexchange.Buy(Price, Amount)
eexchange.Buy(Price, Amount, Msg)
, em que null
será devolvido se a encomenda não for bem sucedida, que é usada para consultar o estado da encomenda.
Se você quiser colocar uma ordem de compra no preço de mercado, exchange.Buy(-1, 0.5)
; se o par de negociação for:ETH_BTC
Algumas plataformas não suportam ordens de mercado, nem o backtest de futuros.
Algumas plataformas têm os requisitos de precisão para preço e quantidade, que podem ser controlados com a função de precisão_N()
Para a negociação de futuros,
Um exemplo de compra uma vez atingido o preço correspondente:
function main(){
while(true){
var ticker = exchange.GetTicker()
var price = ticker.Sell
if(price >= 7000){
exchange.Buy(_N(price+5,2), 1, 'BTC-USDT')
break
}
Sleep(3000)//Sleep 3000ms
}
Log('done')
}
Os parâmetros da ordem de mercado têm significados diferentes.exchange.Sell(-1, 0.2)
, significa vender 0,2 ETH ao preço de mercado.
GetOrder obtém as informações de ordem com base no id de ordem.exchange.GetOrder(OrderId)
, Type
e o valor real da ordemStatus
Os números são números, que representam significados diferentes, mas não são propícios para a memória.Status
O valor de uma encomenda não concluída é 0, o que equivale aORDER_STATE_PENDING
. Todas estas constantes globais podem ser visualizadas no documento... Retorno do resultado:
{
"Id":125723661, //Order id
"Amount":0.01, //Order ammount
"Price":7000, //Order price
"DealAmount":0, //Executed amount
"AvgPrice":0, //executed average price
"Status":0, //0: not completely executed; 1: executed; 2: canceled
"Type":1,//Order type; 0: buy order; 1: sell order
"ContractType":"",//contract type, used in futures trading
"Info":{} //the platform returns the raw information
}
}
Uma estratégia para comprar uma quantidade específica de moeda:
function main(){
while(true){
var amount = exchange.GetAccount().Stocks
var ticker = exchange.GetTicker()
var id = null
if(5-amount>0.01){
id = exchange.Buy(ticker.Sell, Math.min(5-amount,0.2))
}else{
Log('Job completed')
return //return the main function, bot will stop
}
Sleep(3000) //Sleep 3000ms
if(id){
var status = exchange.GetOrder(id).Status
if(status == 0){ //Here you can aslo use "status == ORDER_STATE_PENDING" to judge
exchange.CancelOrder(id)
}
}
}
}
GetOrder obtém a lista de todas as ordens inacabadas do par de negociação atual. Se não houver nenhuma ordem inacabada, retorne uma matriz vazia. O resultado específico da lista de ordens, como
Exemplo de cancelamento de todas as ordens do par de negociação em curso:
function CancelAll(){
var orders = exchange.GetOrders()
for(var i=0;i<orders.length;i++){
exchange.CancelOrder(orders[i].Id) // cancel order by orderID
}
}
function main(){
CancelAll()
while(true){
//do something
Sleep(10000)
}
}
De acordo com o ID da encomenda, cancele a encomenda.exchange.CancelOrder(OrderId)
. Se o cancelamento for bem-sucedido, retorne
Para a criptomoeda, a negociação de futuros é diferente da negociação spot. As funções acima da negociação spot também são aplicáveis à negociação de futuros, e a negociação de futuros individuais tem suas próprias funções. Antes de realizar a negociação de futuros de criptomoeda no programa, você deve estar familiarizado com as operações manuais no site e entender os conceitos básicos, como aberto, fechado, cruzado, isolado, alavancagem, lucro e perda fechados, renda flutuante, margem e outros conceitos, bem como as fórmulas de cálculo correspondentes. Os tutoriais correspondentes podem ser encontrados em várias plataformas de futuros, e você precisa aprendê-los sozinho.
Os contratos perpétuos são semelhantes aos contratos futuros, mas a diferença é que não existe tal conceito de manter posições longas e curtas ao mesmo tempo.
Se a plataforma suportar futuros e spot, como futuros da OKEX e Huobi, você precisa selecionar
O primeiro passo na negociação de futuros é definir o contrato a ser negociado. Tomando OKEX futuros como exemplo, selecione um par de negociação BTC ao criar um bot ou backtesting, e você também precisa definir o contrato semanal, da próxima semana ou trimestral no código.invalid contract type
. Diferente dos pares de negociação à vista, os contratos de futuros geralmente usam moeda de negociação como BTC como margem. Adicionar BTC a um par de negociação geralmente representa um par de negociação BTC_USD que usa BTC como margem. Se houver um contrato de futuros com USDT como margem, um bot precisa ser criado para adicionar o par de negociação BTC_USDT. Por exemplo, contratos perpétuos como Binance OKEX Futures, com contratos cripto-marginados e USDT-marginados.Depois de definir o par de negociação, você também deve definir o tipo de contrato específico, como perpétuo, semanal, semana seguinte, etc. Depois de configurar o contrato, você pode realizar operações como obter cotações de mercado, comprar e vender.
Binance, OKEX, HuobiDM, etc. têm contratos com margem de criptomoedas e contratos com margem de USDT, que precisam ser distinguidos ao adicionar um bot e configurar um contrato.
//OKEX Futures
exchange.SetContractType("swap") // set to perpetual contract
exchange.SetContractType("this_week") // set to weekly contract
exchange.SetContractType("next_week") // set to next week contract
exchange.SetContractType("quarter") // set to quarterly contract
//HuobiDM
exchange.SetContractType("this_week") // set to weekly contract
exchange.SetContractType("next_week") // set to next week contract
exchange.SetContractType("quarter") // set to quarterly contract
exchange.SetContractType("swap") // set to perpetual contract
//Binance Futures
exchange.SetContractType("swap") // set to perpetual contract, and notice that crypto-margined and USDT-margined contracts are all in the perpetual contract
exchange.SetContractType("quarter") // set to quarterly contract
exchange.SetContractType("next_quarter") // set to next quarter contract
//BitMEX
exchange.SetContractType("XBTUSD") // set to perpetual contract
exchange.SetContractType("XBTM19") // the contract settled at a specific time; for more details, please log in BitMEX to check each contract code
//GateIO
exchange.SetContractType("swap") // set to perpetual contract, and do not set the default as swap perpetual contract
//Deribit
exchange.SetContractType("BTC-27APR18") // the contract settled at a specific time; for more details, please log in Deribit to check out
Para obter a lista de informações de posição atual, os futuros OKEX (OKCOIN) podem passar em um parâmetro para especificar o tipo de contrato a ser obtido.[]
A informação da posição é devolvida da seguinte forma. Há muita informação específica, que precisa ser analisada em combinação com o par de negociação.
Tipo de dados | Nome da variável | Descrição |
---|---|---|
Objeto | Informações | a estrutura em bruto que a plataforma retorna |
Número | Nível de margem | tamanho de alavancagem; OKCoin é 10 ou 20, e a posição cruzada de futuros OK retorna 10 (fixo), para a API crua não suporta |
Número | Montante | montante da posição; OKCoin indica a quantidade do contrato (número inteiro sobre 1) |
Número | Número congelado | montante da posição congelada |
Número | Preço | Preço médio da posição |
Número | Margem | margem congelada |
Número | Lucro | commodity futures: o lucro e a perda da marca de posição para o mercado; criptomoeda: unidade de criptomoeda: BTC/LTC, unidade de futuros tradicional: RMB (nota:No caso de uma posição cruzada de futuros OKCoin, refere-se ao lucro e à perda realizados, não ao lucro e à perda da posição. Sob a posição isolada, refere-se ao lucro e à perda da posição.) |
const | Tipo | PD_LONG é a posição longa (CTP usa |
cordel | Tipo de contrato | Os futuros de mercadorias são códigos de contrato e as ações são |
function main(){
exchange.SetContractType("this_week");
var position = exchange.GetPosition();
if(position.length>0){ //especially pay attention to judging the length of position before call, or an error will occur
Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount, "Price:",
position[0].Price, "Profit:", position[0].Profit, "Type:", position[0].Type,"ContractType:", position[0].ContractType)
}
}
Primeiro de tudo, você precisa definir o tamanho da alavancagem; método de invocação:exchange.SetMarginLevel(10)
, onde exchange.SetDirection(Direction)
, que corresponde às posições abertas e fechadas.Ao contrário dos futuros, se um contrato perpétuo não contém os conceitos de longo e curto ao mesmo tempo, ou seja, uma única posição não é permitida.buy
esell
Se ele suporta posições bidirecionais, você precisa definirclosebuy
, closesell
.Relações específicas:
Operação | Parâmetros de direção definidos | Função de Ordem |
---|---|---|
Posições longas abertas | troca.Configurar direcção (( |
troca.Comprar() |
Fechar posição longa | troca.SetDirection (( |
Troca.Venda. |
Posição curta aberta | troca.SetDirection (( |
Troca.Venda. |
Fechar posição curta | troca.SetDirection (( |
troca.Comprar() |
Por fim, há o código específico para posições abertas e fechadas. A quantidade de ordens colocadas varia de plataforma para plataforma. Por exemplo, os futuros Huobi são baseados no número de quantidade de contrato e um contrato é de 100 dólares americanos.
function main(){
exchange.SetContractType("this_week") // for example, set OKEX futures to weekly contract
price = exchange.GetTicker().Last
exchange.SetMarginLevel(10) // set to 10 times of leverage
exchange.SetDirection("buy") // set the order type as buy long
exchange.Buy(price+10, 20) // set contract quantity as 20 orders
pos = exchange.GetPosition()
Log(pos)
Log(exchange.GetOrders()) // check out if there is any unfinished order
exchange.SetDirection("closebuy"); // if it is a perpetual contract, directly set exchange.SetDirection("sell")
exchange.Sell(price-10, 20)
}
Cite um exemplo específico de estratégia de posições fechadas completas:
function main(){
while(true){
var pos = exchange.GetPosition()
var ticker = exchange.GetTicekr()
if(!ticker){
Log('not able to obtain ticker')
return
}
if(!pos || pos.length == 0 ){
Log('no position')
return
}
for(var i=0;i<pos.length;i++){
if(pos[i].Type == PD_LONG){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closebuy')
exchange.Sell(ticker.Buy, pos[i].Amount - pos[i].FrozenAmount)
}
if(pos[i].Type == PD_SHORT){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closesell')
exchange.Buy(ticker.Sell, pos[i].Amount - pos[i].FrozenAmount)
}
}
var orders = exchange.Getorders()
Sleep(500)
for(var j=0;j<orders.length;j++){
if(orders[i].Status == ORDER_STATE_PENDING){
exchange.CancelOrder(orders[i].Id)
}
}
}
}
A negociação de alavancagem de criptomoedas precisa mudar para a conta de alavancagem no código, e outras partes são as mesmas que a negociação spot.
Utilizaçãoexchange.IO("trade_margin") para mudar para o modo de conta de alavancagem; a colocação de uma ordem e a obtenção de ativos da conta acederão à interface da alavancagem da plataforma. Utilizaçãoexchange.IO("trade_normal") para voltar ao modo de conta normal.
Plataformas suportadas:
A negociação de futuros de commodities e a negociação de futuros de criptomoedas são bastante diferentes. Em primeiro lugar, o tempo de negociação de futuros de commodities é muito curto, mas a criptomoeda é negociada por 24 horas; o protocolo de futuros de commodities não é uma API REST comumente usada; a frequência de negociação e o valor da ordem pendente de futuros de commodities são limitados, mas os de criptomoeda são muito soltos, e assim por diante. Portanto, há muitos pontos que precisam de atenção especial ao negociar futuros de commodities, e é recomendado para aqueles que têm rica experiência em operações manuais.https://www.fmz.com/bbs-topic/325Para adicionar empresas de futuros de mercadorias:https://www.fmz.com/bbs-topic/371
Os futuros de commodities implementaram a supervisão transparente em junho de 2019; para o programa individual, os usuários individuais precisam abrir uma conta para solicitar um código de autorização para corretores de futuros (o modelo de informações de aplicativo específico pode ser enviado para o grupo WeChat ou o grupo QQ), o que geralmente leva 4-5 dias; os procedimentos são bastante complicados. Como um provedor de negociação programática, a plataforma FMZ solicitou códigos de autorização de software de vários provedores de serviços de futuros. Os usuários podem usá-los diretamente sem aplicar. Ao adicionar um corretor de futuros, pesquise
Devido às vantagens da estrutura da plataforma FMZ Quant, os usuários também podem adicionar várias contas de corretor de futuros e implementar algumas funções que outros softwares de negociação de futuros de commodities não podem completar, como a síntese de tick de alta frequência; você pode se referir a:https://www.fmz.com/bbs-topic/1184
Em primeiro lugar, como não é uma negociação de 24 horas e requer uma operação de login, é necessário julgar o status do link antes da negociação.exchange.IO("status")
étrue
, o que indica uma conexão bem-sucedida com a plataforma. Se a API for chamada quando o login não for bem-sucedido, _C(exchange.SetContractType,"MA888")
, o que assegurará um login bem sucedido.
Os códigos de aquisição e negociação de cotações de mercado de futuros de commodities são os mesmos que os de futuros de criptomoedas.
function main(){
_C(exchange.SetContractType,"MA888") //If you do not log in successfully, you cannot subscribe to the contract, so better to try again
while(true){
if(exchange.IO("status")){
var ticker = exchange.GetTicker()
Log("MA888 ticker:", ticker)
LogStatus(_D(), "Already connected with CTP !")//_D obtain event
} else {
LogStatus(_D(), "Not connected with CTP !")
Sleep(1000)
}
}
}
Recomenda-se usar a biblioteca de futuros de commodities para negociação (que será descrita mais tarde), o código será muito simples neste momento, e não há necessidade de lidar com detalhes tediosos.https://www.fmz.com/strategy/57029
function main() {
// Use the CTA strategy framework of commodity futures library
$.CTA(Symbols, function(st) {
var r = st.records
var mp = st.position.amount
var symbol = st.symbol
/*
"r" represents K-line, "mp" indicates the position amount of the current variety; positive number means long position, negative number means short position, and 0 means no position; "symbol" is the variety name
if the return value is n:
n = 0 : full close positions (no matter now they are long or short)
n > 0 : if right now long positions are held, add n long positions; if now they are short positions, close n short posiitons; if n is over the position amount right now, reverse to open long positions
n < 0 : if right now short positions are held, add n short positions; if now they are long positions, close n long posiitons; if -n is over the position amount right now, reverse to open short positions
*/
if (r.length < SlowPeriod) {
return
}
var cross = _Cross(TA.EMA(r, FastPeriod), TA.EMA(r, SlowPeriod));
if (mp <= 0 && cross > ConfirmPeriod) {
Log(symbol, "Golden Cross Period", cross, "the moment position", mp);
return Lots * (mp < 0 ? 2 : 1)
} else if (mp >= 0 && cross < -ConfirmPeriod) {
Log(symbol, "Death Cross Period", cross, "the moment position", mp);
return -Lots * (mp > 0 ? 2 : 1)
}
});
}
Os futuros de commodities usam o protocolo CTP, e todas as cotações de mercado e as execuções de ordens serão notificadas apenas após as mudanças, enquanto consultas sobre ordens, contas e posições são consultas ativas.GetTicker
, GetDepth
eGetRecords
, todos precisam ter dados em cache para obter os dados mais recentes. Se não houver dados, ele esperará até que haja dados, por isso não é necessário que a estratégia use
Se você quiser obter dados toda vez que você obter as cotações de mercado, mesmo que seja dados antigos, você pode mudar para o modo de atualização imediata das cotações de mercadoexchange.IO("mode", 0)
Neste momento, a estratégia não pode ser escrita como orientada por eventos, e um evento exchange.IO("mode", 1)
para voltar ao modo de cache padrão.
No entanto, se houver vários contratos, é possível que um dos contratos não atualize as cotações de mercado, resultando no bloqueio da interface para obter cotações de mercado, e as atualizações de cotações de outros contratos também não possam ser obtidas. Para resolver esse problema, o modo de atualização imediata pode ser usado, mas é inconveniente escrever estratégias de alta frequência.exchange.IO("wait")
Se múltiplos objetos de troca são adicionados, o que é raro em futuros de commodities, você pode usarexchange.IO("wait_any")
, e o
Impulso das alterações do mercado:{Event:"tick", Index: platform index (in the order of the platforms added in the bot), Nano: event of nanosecond-level time, Symbol: contract name}
Push de ordem:{Event:"order", Index:Exchange index, Nano:Event of nanosecond-level time, Order:Order information (same as GetOrder)}
Neste momento, a estrutura da estratégia pode ser escrita como:
function on_tick(symbol){
Log("symbol update")
exchange.SetContractType(symbol)
Log(exchange.GetTicker())
}
function on_order(order){
Log("order update", order)
}
function main(){
while(true){
if(exchange.IO("status")){ //Judge the link status
exchange.IO("mode", 0)
_C(exchange.SetContractType, "MA888")//Subscribe to MA; only the subscription request for the first time is ture, and the later ones are program switches, which do not consume time
_C(exchange.SetContractType, "rb888")//Subscribe to rb
while(true){
var e = exchange.IO("wait")
if(e){
if(e.event == "tick"){
on_tick(e.Symbol)
}else if(e.event == "order"){
on_order(e.Order)
}
}
}
}else{
Sleep(10*1000)
}
}
}
Observe também a diferença entre futuros de commodities e plataformas de criptomoedas. Por exemplo,
exchange.IO("instruments"): devolve a lista de todos os contratos na plataforma {nome do contrato: detalhes} em forma de dicionário e suporta apenas bots.exchange.IO("produções"): devolve a lista de todos os itens da plataforma {nome do contrato: detalhes} em forma de dicionário e suporta apenas bots.exchange.IO("subscrito"): retorna as cotações de mercado subscritas na plataforma em forma de dicionário e suporta apenas bots.
OContractType
Os futuros de CTP tradicionais referem-se ao ID do contrato, que é sensível a minúsculas e minúsculas.exchange.SetContractType("au1506")
. Após o contrato ser definido com sucesso, ele retornará as informações detalhadas do contrato, como o valor mínimo de compra, taxa de serviço, tempo de entrega, etc. Ao assinar vários contratos, apenas a primeira vez que um pedido de assinatura é realmente enviado, e então o par de negociação é simplesmente trocado no nível de código, o que não leva tempo. O principal contrato contínuo é o código 888, como MA888, o contrato de taxa contínua é 000, como MA000; 888 e 000 são negociações de contratos virtuais que apenas suportam backtest, e bots reais apenas suportam cotações de mercado.No entanto, a Mylanguage pode operar o contrato principal, e o programa mudará automaticamente as posições, ou seja, fechará as posições não principais e abrirá novas posições nas posições principais.
O login falhado não pode definir contratos, mas retornará imediatamente, então você pode tentar por
A SetDirection
pode obter quatro parâmetros:buy, closebuy, sell, closesell
Os futuros de commodities têm maisclosebuy_today
eclosesell_today
, indicando o encerramento das posições correntes; o valor por defeito éclosebuy/ closesell
, indicando o fechamento de posições de ontem; apenas as variedades da Shanghai Futures Exchange são divididas em fechamento de hoje e fechamento de ontem, o que pode afetar a taxa de serviço, por isso é necessário dar prioridade ao fechamento de posições de ontem. Para futuros tradicionais do CTP, você pode definir o segundo parâmetro como
Operação | Parâmetros de direção definidos | Função de Ordem |
---|---|---|
Posições longas abertas | troca.Configurar direcção (( |
troca.Comprar() |
Fechar posição longa | troca.SetDirection (( |
Troca.Venda. |
Posição curta aberta | troca.SetDirection (( |
Troca.Venda. |
Fechar posição curta | troca.SetDirection (( |
troca.Comprar() |
O exemplo a seguir é uma função de posição de fechamento específica. Observe que este exemplo é muito simples. Você também deve considerar se está dentro do tempo de negociação, como tentar novamente a ordem pendente se não estiver completamente preenchida, qual é o volume máximo de ordem, se a frequência é muito alta e se é preço deslizante ou preço de mercado e assim por diante.é um pacote de biblioteca das plataformas sugeridas para abertura e fechamento de posições em bots reais:https://www.fmz.com/strategy/12961Há uma introdução específica na secção da biblioteca, e também é recomendável estudar os códigos fonte da biblioteca.
function Cover(contractType, amount, slide) {
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType != contractType) {
continue;
}
var depth = _C(e.GetDepth);
if (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) {
exchange.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy");
exchange.Sell(depth.Bids[0]-slide, amount, contractType, positions[i].Type == PD_LONG ? "Close today" : "Close yesterday", 'Bid', depth.Bids[0]);
} else {
exchange.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
exchange.Buy(depth.Asks[0]+slide, amount, contractType, positions[i].Type == PD_SHORT ? "Close today" : "Close yesterday", 'Ask', depth.Asks[0]);
}
}
}
Os futuros de commodities suportam tipos de ordens personalizados (suporte para bots, mas não para backtest), que são especificados por sufixo, anexado a
exchange.SetDirection("buy_ioc");
exchange.SetDirection("sell_gtd-20170111")
Sufixos específicos:
Por padrão, as interfaces abertas nos corretores de futuros de commodities são todas interfaces CTP. Se necessário, elas podem ser substituídas por interfaces Esunny. Através da encapsulamento do FMZ, o método de invocação é o mesmo. A diferença é que as contas, ordens e posições estão todas no modo push, então o docker manterá esses dados localmente e retornará imediatamente quando a interface correspondente for chamada, sem realmente fazer um pedido.
Protocolo Esunny Tipos de encomendas personalizadas são:
Ao registrar um registro de log na interface do bot, e adicionar o caractere Log('Push to WeChat@')
.
A cor do log também pode ser personalizada, tais comoLog('this is a log in red font #ff0000')
.
#ff0000
é o hexadecimal da cor RGB, indicando que todos os arquivos de log são armazenados no banco de dados SqLit do bot no diretório onde o docker está localizado, que pode ser baixado e aberto com o software do banco de dados, ou pode ser usado para copiar backup e restaurar (nome do banco de dados e o bot id são os mesmos).
Ele registra os lucros e desenha a curva de lucro na interface do bot, que pode ser retida após o bot ser reiniciado.LogProfit(1000)
Observe que o parâmetro deLogProfit
não é necessariamente o lucro, e pode ser qualquer número e precisa ser preenchido por si mesmo.
Se o estado do bot, uma vez que o registro será salvo primeiro e atualizado continuamente, precisa das informações apenas para exibição e não para salvar, você pode usar oLogStatus
Os parâmetros deLogStatus
são strings, que também podem ser usados para representar as informações da tabela.
Um exemplo de uma tabela de exibição específica de posição real de bot:
var table = {type: 'table', title: 'position information', cols: ['Column1', 'Column2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]};
LogStatus('`' + JSON.stringify(table) + '`'); // After serialization, JSON will be added the character "'" on both sides, which is regarded as a comlpex messag format (now supporting tables)
LogStatus('The first line information\n`' + JSON.stringify(table) + '`\nthe third line information'); // the table information can be displayed in multiple lines
LogStatus('`' + JSON.stringify([table, table]) + '`'); // Multiple tables are supported to be displayed at the same time, which will be displayed in one group by TAB
LogStatus('`' + JSON.stringify(tab1) + '`\n' + '`' + JSON.stringify(tab2) + '`\n'); // Multiple tables are displayed up and down by arrangement
Seu parâmetro é o número de milissegundos, comoSleep(1000)
Devido à frequência de acesso limitada de todas as plataformas, o tempo de sono deve ser adicionado ao loop infinito em estratégias gerais.
Depois de o bot ser reiniciado, o programa reiniciará._G
É muito conveniente e prático, e pode salvar o conteúdo serializado JSON._G
função é escrito emonexit()
, de modo a que, sempre que a estratégia for interrompida, as informações necessárias sejam salvas automaticamente.
Se quiser guardar mais dados formatados, a função _G não é adequada, mas