Recentemente, o grupo oficial da FMZ discutiu mais estratégias do tipo Martin, e não houve muitas estratégias de Martin sobre contratos de moeda digital na plataforma. Por isso, aproveitei a oportunidade para criar uma estratégia de Martin simples para futuros de moeda digital. Por que dizer estratégia de Martin, pois o risco potencial é grande, não foi totalmente projetado de acordo com a estratégia de Martin?
Este artigo trata principalmente de aprender a partir do design de estratégias do tipo Martin, e a ideia estratégica em si já está bem clara. Como usuários do FMZ, nós pensamos mais no design estratégico.
Quando se desenha uma estratégia de futuros de moeda digital, é frequente usar os dados de ganhos totais; porque os ganhos são calculados, especialmente quando os ganhos flutuantes são calculados; porque os valores mobiliários ocupam o valor da garantia, os títulos pendentes também ocupam; quando se chama a interface API da plataforma FMZ.exchange.GetAccount()
Os dados obtidos são os ativos disponíveis e os ativos congelados. Na verdade, a maioria das exchanges de futuros de moeda digital fornece esse dado, mas o FMZ não possui um pacote uniforme para esse atributo.
Então, nós criamos funções diferentes para cada uma das bolsas, para obter esses dados:
// OKEX V5 获取总权益
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
// 币安期货
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
No códigototalEquity
E então nós escrevemos uma função como uma entrada de chamada, para chamar a função correspondente de acordo com o nome da troca.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
Antes de projetar funções principais, a lógica principal. Também precisamos fazer alguns preparativos para projetar funções auxiliares.
Cancelar todas as listas pendentes atuais
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
Sleep(500)
}
}
Esta função é, acredito, familiar para quem frequenta o código do exemplo de estratégia no FMZ Strategy Square, onde muitas estratégias usaram um design semelhante.
Operações de sub-ordens de futuros
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
A negociação de futuros tem quatro direções: aberto longo, aberto curto, aberto curto, aberto curto, aberto curto e aberto curto. Portanto, projetamos quatro funções de sub-ordens para corresponder a essas operações. Se considerarmos apenas sub-ordens, existem alguns fatores necessários: direção, preço do sub-ordem e volume do sub-ordem.
Por isso, também criamos um projeto chamado:trade
A função para tratar quando方向(distance)
、下单价格(price)
、下单量(amount)
A maioria das vezes, o que é preciso é uma operação clara.
As chamadas de funções openLong, openShort, coverLong e coverShort são feitas por uma única pessoa.trade
A função executa a função real, ou seja, encomenda no mercado de futuros de acordo com uma direção, preço ou quantidade estabelecida.
A ideia estratégica é simples: pendurar a venda ("fazer vazios") ou a compra ("fazer mais") a uma certa distância abaixo do preço atual na linha de base. Ao concluir o negócio, todos os pedidos remanescentes são cancelados e, em seguida, um novo pedido de liquidação é pendurado a uma certa distância de acordo com o preço do estoque, pendurando um pedido de aumento de estoque no preço atual após a atualização, mas sem dobrar o volume do pedido.
Trabalho inicial Para fazer a listagem, precisamos de duas variáveis globais para registrar o ID do pedido.
var buyOrderId = null
var sellOrderId = null
A opção de usar o disco OKEX_V5 é então projetada nos parâmetros da interface da política, então há algumas manipulações a serem feitas no código:
var exName = exchange.GetName()
// 切换OKEX V5模拟盘
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
A interface também tem uma opção para reiniciar todas as informações, então o código também tem um tratamento correspondente:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
Nós apenas corremos um contrato perpétuo, então aqui está escrito que morremos, apenas estabelecidos como um contrato perpétuo.
exchange.SetContractType("swap")
Então, devemos também considerar o problema da precisão do preço do pedido, da precisão do pedido, se a precisão não for bem definida, a precisão é perdida no cálculo da estratégia, muitos números fracos de dados podem facilmente causar a rejeição da interface do mercado quando o pedido é feito.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
Funções de recuperação de dados simples de desenhar
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "获取初始权益失败"
}
} else {
totalEq = recoverTotalEq
}
}
Se você quiser especificar o total de direitos da conta inicial quando a política for executada, você pode definir o parâmetrototalEq
Se o parâmetro for definido como -1, a política lê os dados de benefícios totais armazenados. Se não tiver dados de benefícios totais armazenados, o benefício total inicial é o benefício total da estratégia, com o benefício total atualmente lido como o progresso da execução da estratégia.
A lógica principal Após o trabalho inicial, finalmente chegamos à parte da lógica principal da estratégia, e para facilitar a explicação, eu escrevi diretamente a explicação na notação do código.
while (1) { // 策略主要逻辑设计为一个死循环
var ticker = _C(exchange.GetTicker) // 首先读取当前行情信息,主要用到最新成交价
var pos = _C(exchange.GetPosition) // 读取当前持仓数据
if (pos.length > 1) { // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
Log(pos)
throw "同时有多空持仓" // 抛出错误,让策略停止
}
// 根据状态而定
if (pos.length == 0) { // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
// 未持仓了,统计一次收益
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // 挂开多仓的买单
sellOrderId = openShort(ticker.Last + targetProfit, amount) // 挂开空仓的卖单
} else if (pos[0].Type == PD_LONG) { // 有多头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = openLong(price - targetProfit * n, amount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) { // 有空头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, amount)
}
if (!sellOrderId || !buyOrderId) { // 如果有一边挂单失败就取消所有挂单,重来
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // 挂单完成,开始监控订单
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
}
}
if (!isFindSellId && !isFindBuyId) { // 检测到买卖单都成交了
cancelAll()
break
} else if (!isFindBuyId) { // 检测到买单成交
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) { // 检测到卖单成交
Log("卖单成交")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
A lógica e o projeto são explicados.
A estratégia deve passar por uma experiência do dia 19 de maio.
Como pode ser visto, a estratégia do tipo Martin ainda é um pouco arriscada.
A estratégia é endereçada:https://www.fmz.com/strategy/294957
A estratégia é usada principalmente para a aprendizagem, e o ouro e a prata são usados com cuidado ~!
Lisa20231O que é que ele está a fazer? if (!isFindSellId &&!isFindBuyId) { // detecta que todas as encomendas foram feitas Quando se detecta um pedido, se o comprador fizer um comprovativo de compra e venda ao mesmo tempo, e se o comprador fizer um comprovativo de compra e venda ao mesmo tempo, será um erro?
Neo1898A outra questão é se o modelo de contrato é de estoque inteiro ou de estoque por estoque.
Neo1898Se o contrato foi aberto, por que não foi estabelecido o dobro do contrato? Quantas vezes a venda é feita?
Nuvens levesGraças a DreamDa, eu finalmente entendo tudo. Depois, aprendeu a monitorar a lista pendurada e escreveu um Martin bilateral. Durante dois dias, escreveu 580 linhas. Graças ao seu esforço.
hk quantidade/upload/asset/1a9ebf427c4e2cbf1c327.png Falso verdadeiro em troca?
Sonhos custam oito dígitosSe
Sonhos custam oito dígitosTotal dos direitos de propriedade
zeroO que fazer para parar o dano?
btcrobotMartin, refazemos e é zero.
WqyE se você não percebe o número de dígitos é igual a igual, então o n é sempre igual a 1.
LvdaleiA estratégia é multi-espaço, duplo-aberto ou separado?
Inventor quantificado - sonho pequenoNão lança erros. Ainda cancela todos os pedidos pendurados, salta do ciclo atual e continua a fazer a lógica.
Inventor quantificado - sonho pequenoEm geral, é melhor usar o estoque inteiro.
Inventor quantificado - sonho pequenoA alavancagem pode ser definida no mercado, dependendo das preferências de risco.
Inventor quantificado - sonho pequenoO total de nuvens é 666!
Inventor quantificado - sonho pequenoEssa variável é chamada isFindBuyId e não é apropriada.
Inventor quantificado - sonho pequenoA estratégia não foi projetada para parar o prejuízo.
Inventor quantificado - sonho pequenoHa ha, o destino de Martin. Este artigo é principalmente sobre estratégias de ensino, sem muita atenção.
Inventor quantificado - sonho pequenoEsse N é usado para alterações posteriores, como pensar em n vezes a distância de armazenamento, que pode ser definida temporariamente como 1⁄2.
Inventor quantificado - sonho pequenoO que você está fazendo é errado.