avatar of 发明者量化-小小梦 发明者量化-小小梦
focar em Mensagem privada
4
focar em
1271
Seguidores

Contrato de moeda digital robô de negociação de cópia simples

Criado em: 2021-04-07 21:30:05, atualizado em: 2024-12-05 21:59:36
comments   11
hits   4372

Contrato de moeda digital robô de negociação de cópia simples

Contrato de moeda digital robô de negociação de cópia simples

Em artigos anteriores, implementamos um robô simples de copy trading spot. Hoje, implementaremos uma versão contratada de um robô simples de copy trading.

Ideias de design

Há uma grande diferença entre a versão contratada do robô de copy trading e a versão spot. O spot copy trading pode ser alcançado principalmente monitorando mudanças nos ativos da conta. A versão de futuros requer monitoramento de mudanças nas posições das contas. Portanto, a situação na versão de futuros é mais complicada, porque os futuros têm posições longas, posições curtas e contratos diferentes. Essa série de detalhes precisa ser processada. A ideia central é monitorar mudanças nas posições. Acione a ação de cópia com base na mudança de posição. Quando foi projetado, a intenção era lidar com posições longas e curtas ao mesmo tempo, mas descobriu-se que isso se tornaria muito complicado. Após analisar o problema, decidiu-se tratar as posições longas e curtas separadamente.

Implementação da estratégia

Parâmetros de estratégia:

Contrato de moeda digital robô de negociação de cópia simples

O backtesting é suportado, e você pode usar diretamente as configurações padrão para fazer backtesting de observações.

Código fonte da estratégia:

/*backtest
start: 2021-03-18 00:00:00
end: 2021-04-07 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"},{"eid":"Futures_OKCoin","currency":"BTC_USD"},{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
*/

function test() {
    // 测试函数
    var ts = new Date().getTime()    
    if (ts % (1000 * 60 * 60 * 6) > 1000 * 60 * 60 * 5.5) {
        Sleep(1000 * 60 * 10)
        var nowPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
        var longPosAmount = nowPosAmount.long
        var shortPosAmount = nowPosAmount.short
        var x = Math.random()
        if (x > 0.7) {
            exchange.SetDirection("buy")
            exchange.Buy(-1, _N(Math.max(1, x * 10), 0), "参考账户测试开单#FF0000")
        } else if(x < 0.2) {
            exchange.SetDirection("sell")
            exchange.Sell(-1, _N(Math.max(1, x * 10), 0), "参考账户测试开单#FF0000")
        } else if(x >= 0.2 && x <= 0.5 && longPosAmount > 4) {
            exchange.SetDirection("closebuy")
            exchange.Sell(-1, longPosAmount, "参考账户测试平仓#FF0000")
        } else if(shortPosAmount > 4) {
            exchange.SetDirection("closesell")
            exchange.Buy(-1, _N(shortPosAmount / 2, 0), "参考账户测试平仓#FF0000")
        }
    }
}

function getPosAmount(pos, ct) {
    var longPosAmount = 0
    var shortPosAmount = 0
    _.each(pos, function(ele) {
        if (ele.ContractType == ct && ele.Type == PD_LONG) {
            longPosAmount = ele.Amount
        } else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
            shortPosAmount = ele.Amount
        }
    })
    return {long: longPosAmount, short: shortPosAmount}
}

function trade(e, ct, type, delta) {
    var nowPosAmount = getPosAmount(_C(e.GetPosition), ct)
    var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
    if (delta > 0) {
        // 开仓
        var tradeFunc = type == PD_LONG ? e.Buy : e.Sell
        e.SetDirection(type == PD_LONG ? "buy" : "sell")
        tradeFunc(-1, delta)
    } else if (delta < 0) {
        // 平仓
        var tradeFunc = type == PD_LONG ? e.Sell : e.Buy
        e.SetDirection(type == PD_LONG ? "closebuy" : "closesell")
        if (nowAmount <= 0) {
            Log("未检测到持仓")
            return 
        }
        tradeFunc(-1, Math.min(nowAmount, Math.abs(delta)))
    } else {
        throw "错误"
    }
}

function main() {
    LogReset(1)
    if (exchanges.length < 2) {
        throw "没有跟单的交易所"
    }
    var exName = exchange.GetName()
    // 检测参考交易所
    if (!exName.includes("Futures_")) {
        throw "仅支持期货跟单"
    }
    Log("开始监控", exName, "交易所", "#FF0000")
    
    // 检测跟单交易所
    for (var i = 1 ; i < exchanges.length ; i++) {
        if (exchanges[i].GetName() != exName) {
            throw "跟单的期货交易所和参考交易所不同!"
        }
    }
    
    // 设置交易对、合约
    _.each(exchanges, function(e) {
        if (!IsVirtual()) {
            e.SetCurrency(refCurrency)
            if (isSimulate) {
                if (e.GetName() == "Futures_OKCoin") {
                    e.IO("simulate", true)
                }
            }
        }
        e.SetContractType(refCt)
    })

    var initRefPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
    while(true) {
        if (IsVirtual()) {    // 回测时才模拟
            test()            // 测试函数,模拟参考账户主动交易,触发跟单账户跟单        
        }
        Sleep(5000)
        var nowRefPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
        var tbl = {
            type : "table", 
            title : "持仓",
            cols : ["名称", "标签", "多仓", "空仓", "账户资产(Stocks)", "账户资产(Balance)"],
            rows : []
        }
        _.each(exchanges, function(e) {
            var pos = getPosAmount(_C(e.GetPosition), refCt)
            var acc = _C(e.GetAccount)
            tbl.rows.push([e.GetName(), e.GetLabel(), pos.long, pos.short, acc.Stocks, acc.Balance])
        })
        LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
        
        // 计算仓位变动量
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // 检测变动
        if (longPosDelta == 0 && shortPosDelta == 0) {
            continue
        } else {
            // 检测到仓位变动
            for (var i = 1 ; i < exchanges.length ; i++) {
                // 执行多头动作
                if (longPosDelta != 0) {
                    Log(exchanges[i].GetName(), exchanges[i].GetLabel(), "执行多头跟单,变动量:", longPosDelta)
                    trade(exchanges[i], refCt, PD_LONG, longPosDelta)
                }
                // 执行空头动作
                if (shortPosDelta != 0) {
                    Log(exchanges[i].GetName(), exchanges[i].GetLabel(), "执行空头跟单,变动量:", shortPosDelta)
                    trade(exchanges[i], refCt, PD_SHORT, shortPosDelta)
                }
            }
        }

        // 执行跟单操作后,更新
        initRefPosAmount = nowRefPosAmount
    }
}

teste

Como o OKEX pode usar o disco de simulação OKEX após atualizar a interface V5, usei duas CHAVES de API do disco de simulação OKEX para testes práticos.

O primeiro objeto de troca adicionado é a troca de referência, e a troca de cópia seguirá essa conta de troca para operar. Na página de simulação de negociação da OKEX, coloque manualmente 3 contratos trimestrais baseados em moedas ETH com base na conta da exchange.

Contrato de moeda digital robô de negociação de cópia simples

Pode-se observar que o mercado real detecta as mudanças nas posições das contas de câmbio de referência e então acompanha as operações.

Contrato de moeda digital robô de negociação de cópia simples

Vamos tentar fechar as duas posições de contrato que acabamos de abrir. As posições após o fechamento são como mostrado na figura:

Contrato de moeda digital robô de negociação de cópia simples

Acompanhe a operação em tempo real e feche 2 contratos.

Contrato de moeda digital robô de negociação de cópia simples

Esta estratégia é projetada de forma simples e fácil de entender, sem nenhuma otimização. A melhoria ainda precisa lidar com detalhes como detecção de ativos ao seguir ordens. Para simplificar o design, ordens de mercado são usadas para seguir ordens . A estratégia fornece apenas ideias de aprendizado, e a negociação real será otimizada de acordo com as necessidades.

Endereço estratégico: https://www.fmz.com/strategy/270012

Bem-vindo para deixar uma mensagem.