Segurança triangular.ipynb
Em [1]:
var fmz = require("fmz") // Import the talib, TA, and plot libraries automatically after import.
var task = fmz.VCtx({
start: '2019-04-09 17:49:00',
end: '2019-04-09 18:00:00',
period: '1m',
exchanges: [{"eid":"Huobi","currency":"ETH_BTC", "balance":1, "stocks":10},{"eid":"OKEX","currency":"ETH_USDT","balance":10000,"stocks":1}, {"eid":"OKEX","currency":"BTC_USDT","balance":10000,"stocks":1}]
})
Exibição das informações iniciais da conta de câmbio e dos marcadores:
Em [2]:
var accA = exchanges[0].GetAccount()
accA
Fora[2]: { Saldo: 1, FrozenBalance: 0, Stocks: 10, FrozenStocks: 0 }
Em [3]:
var accB = exchanges[1].GetAccount()
accB
Fora[3]: { Saldo: 10 000, FrozenBalance: 0, Stocks: 1, FrozenStocks: 0 }
Em [4]:
var accC = exchanges[2].GetAccount()
accC
Fora[4]: { Saldo: 10 000, FrozenBalance: 0, Stocks: 1, FrozenStocks: 0 }
Em [5]:
var initSumBTC = accA.Balance + accC.Stocks
initSumBTC
Fora[5]: 2 - Não.
Em [6]:
var initSumETH = accA.Stocks + accB.Stocks
initSumETH
Fora[6]: - 11.
Em [7]:
var initSumUSDT = accB.Balance + accC.Balance
initSumUSDT
Fora[7]: 20000
Podemos ver que o número total inicial de BTC é 2, o número total de ETH é 11, e o número total de USDT é 20000.
Em [8]:
var tickerA = exchanges[0].GetTicker()
tickerA
Fora[8]: Hora: 1554831960000, Alto: 0,03396501, Baixo: 0,03396499, Venda: 0,03396501, Comprar: 0,03396499, Último: 0,033965, Volume: 4696,555, Interesse aberto: 0 }
Em [9]:
var tickerB = exchanges[1].GetTicker()
tickerB
Fora[9]: Hora: 1554831960000, Alto: 175.08000001, Baixo: 175,07999999, Venda: 175.08000001, Compra: 175.07999999, Último: 175.08, Volume: 20730.37, Interesse aberto: 0 }
Em [10]:
var tickerC = exchanges[2].GetTicker()
tickerC
Fora[10]: Hora: 1554831960000, Alto: 5161.90000001, Baixo: 5161.89999999, Venda: 5161.90000001, Compra: 5161.89999999, Último: 5161,9. Volume: 2109.9292, Interesse aberto: 0 }
Pode-se ver que o objeto da Exchange A, Exchange B e da transação é o ETH, ou seja, a exchange A/B pode realizar operações de cobertura indireta, mas não pode cobrir diretamente porque as moedas de preços são diferentes.
Suponha que a troca A executa uma operação de compra deexchanges[0].Buy(price, amount)
, e o preço vendido pela contraparte é utilizado como preço de encomenda ao comprar, ou seja,tickerA.Sell
A bolsa B realiza uma operação de venda para cobrança, ou seja,exchanges[1].Sell(price, amount)
, e o preço que a contraparte deseja comprar é utilizado como preço da ordem ao vender, ou seja,tickerB.Buy
Porque a troca A consumiuBTC
quando comprar, e troca B obtido USDT quando vender, troca A precisa substituirUSDT
com BTC para compensar o BTC consumido pela troca A, ou seja, troca C executaexchanges[2].Buy(price, amount)
, e trocaUSDT
comBTC
Para comprar, a troca C precisa ver o preço de venda da contraparte, ou seja,tickerC.Sell
. O preço de compra da troca A deve ser menor que o preço de venda da troca B, então a troca C pode comprar de volta BTC consumido pela troca A com menos USDT. Você ganhará a diferença da quantia USDT.
Então é assim:
Em [11]:
var diffB2A = tickerA.Sell - tickerB.Buy / tickerC.Sell // diffB2A means that Exchange B sells ETH coins and Exchange A buys ETH coins, which is logically equivalent to the transfer of ETH from Exchange B to Exchange A.
diffB2A
Fora[11]: 0,000047266535449966285
Obviamente, o preço de compra da Bolsa A é superior ao da Bolsa B e da Bolsa C, e a cobertura é obviamente uma perda de dinheiro. A outra direção de cobertura é a mesma. A Exchange A executa a operação de venda de ETH, a Exchange B executa a operação de compra de ETH e a Exchange C vende BTC por USDT. A obtenção da moeda é sempre equilibrada e apenas o USDT aumenta ou diminui (ou seja, a diferença ganha).
Em [12]:
var diffA2B = tickerA.Buy - tickerB.Sell / tickerC.Buy
diffA2B
Fora[12]: 0,000047246531444007644 (em inglês)
Vamos fazer umtickerA.Buy - tickerB.Sell / tickerC.Buy
operação de cobertura para descobrir como cada um dos valores muda.
Em [13]:
var idA = exchanges[0].Sell(tickerA.Buy, 1)
var nowAccA = exchanges[0].GetAccount()
nowAccA // We can see that the fee is deducted from the BTC.
Fora[13]: Saldo: 1,03389706, FrozenBalance: 0, Reservas: 9, FrozenStocks:
Em [14]:
var orderA = exchanges[0].GetOrder(idA)
orderA
Fora [1]:
{Id: 1,
Preço: 0.03396499,
Montante: 1,
Transação: 1.
Preço médio: 0.03396499,
Tipo: 1,
Deslocamento: 0,
Situação: 1,
Tipo de contrato:
Em [15]:
var feeRatioA = 0.002 // The default fee for backtesting is 0.2%, i.e. 0.002.
var feeA = orderA.DealAmount * orderA.AvgPrice * feeRatioA // Exchange A trading fees, BTC denominated.
feeA
Fora[15]: 0,00006792998000000001
Em [16]:
var idB = exchanges[1].Buy(tickerB.Sell, 1)
var nowAccB = exchanges[1].GetAccount()
nowAccB
Fora [1]: Saldo: 9824.56983998, FrigoríficoBalance: 0, Reservas: 2, FrozenStocks:
Em [17]:
var orderB = exchanges[1].GetOrder(idB)
orderB // We can see that the fee is deducted from the USDT.
Fora [1]:
{Id: 1,
Preço: 175.08000001,
Montante: 1,
O montante do acordo é: 1
Preço médio: 175.08000001,
Tipo: 0,
Deslocamento: 0,
Situação:
ContractType:
Em [18]:
var feeRatioB = 0.002
var feeB = orderB.DealAmount * orderB.AvgPrice * feeRatioB / tickerC.Last // B exchange fees, converted to BTC denomination.
feeB
Fora [1]: 0,00006783548693698057
Em [19]:
var idC = exchanges[2].Sell(tickerC.Buy, nowAccA.Balance - accA.Balance)
var nowAccC = exchanges[2].GetAccount()
nowAccC
Fora [1]: Saldo: 10174.12327555, FrigoríficoBalance: 0, Reservas: 0,9662. FrozenStocks:
Em [20]:
var orderC = exchanges[2].GetOrder(idC)
orderC // We can see that the fee is deducted from the USDT.
Fora [1]:
{Id: 1,
Preço: 5161.89999999,
Montante: 0,0338,
O valor da transacção é de 0,0338.
Preço médio: 5161.89999999,
Tipo: 1,
Deslocamento: 0,
Situação:
Tipo de contrato:
Em [21]:
var feeRatioC = 0.002
var feeC = orderC.DealAmount * orderC.AvgPrice * feeRatioC / tickerC.Last // Fees for C exchange transactions, BTC denominated.
feeC
Fora[21]: 0,00006759999999986903
Calcular a informação total sobre os ativos após cobertura:
Em [22]:
var nowSumBTC = nowAccA.Balance + nowAccC.Stocks
nowSumBTC
Fora[22]: 2.00009706
Em [23]:
var nowSumETH = nowAccA.Stocks + nowAccB.Stocks
nowSumETH
Fora[23]: 11
Em [24]:
var nowSumUSDT = nowAccB.Balance + nowAccC.Balance
nowSumUSDT
Fora[24]: 19998.69311553
Em [25]:
nowSumBTC - initSumBTC
Fora[25]: 0,00009705999999987114
Em [26]:
tickerC.Buy * (nowSumBTC - initSumBTC) // Excess BTC converted to USDT
Fora[26]: 0,5010140139983642
Em [27]:
nowSumUSDT + tickerC.Buy * (nowSumBTC - initSumBTC) - initSumUSDT // Profit and loss are calculated based on the movement of the account assets and both are denominated in USDT.
Fora[27]: - 0,8058704560025944
Em [28]:
(diffA2B - (feeA + feeB + feeC)) * tickerC.Buy // Profit and loss based on price difference, denominated in USDT.
Fora[28]: -0,8058703331189396 -0,8058703331189396 -0,8058703331189396 -0,8058703331189396 -0,8058703331189396 -0,8089396 -0,8058703331189396 -0,8089396 -0,805870333331189396 -0,8089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396 -0,089396
Como podemos ver, a diferença de preço no caso da cobertura é diferencial A2B: 0,000047246531444007644. As taxas para as três coberturas, convertidas em BTC são: feeA + feeB + feeC.
Em [29]:
feeA + feeB + feeC
Fora[29]: 0,0002033654669368496
Pode-se ver que, para tal cobertura triangular, a diferença de preço deve ser maior do quefeeA+feeB+feeC
pelo menos, o que significa nenhuma perda, nenhum ganho, e para fazer um lucro deve ser maior do que a diferença de preço.
No momento, através do cálculo da comparação de contas e do cálculo da diferença de preço, é uma perda.
Modifiquei uma versão, de modo que as taxas de manuseio calculadas pelo parâmetro de taxas de manuseio sejam exactamente iguais ao lucro da diferença de preços do mercado testado por este modelo para observação comparativa.
Pode-se observar que, na condição de defeito das taxas de gestão (2 ‰ por defeito), quando a diferença de cobertura é de 0,000047246531444007644 BTC, a cobertura é uma perda e a perda é de cerca de -0,8058704560025944.
Cobertura triangular (ajuste das taxas de gestão).ipynb
Em [1]:
var fmz = require("fmz") // Import talib, TA, plot libraries automatically after introduction.
var task = fmz.VCtx({
start: '2019-04-09 17:49:00',
end: '2019-04-09 18:00:00',
period: '1m',
exchanges: [{"eid":"Huobi","currency":"ETH_BTC", "balance":1, "stocks":10,"fee":[0.04,0.04]},{"eid":"OKEX","currency":"ETH_USDT","balance":10000,"stocks":1,"fee":[0.04,0.04]}, {"eid":"OKEX","currency":"BTC_USDT","balance":10000,"stocks":1,"fee":[0.04,0.04]}]
})
Exibição das informações iniciais da conta de câmbio e do ticker:
Em [2]:
var accA = exchanges[0].GetAccount()
accA
Fora[2]: { Saldo: 1, FrozenBalance: 0, Stocks: 10, FrozenStocks: 0 }
Em [3]:
var accB = exchanges[1].GetAccount()
accB
Fora[3]: { Saldo: 10 000, FrozenBalance: 0, Stocks: 1, FrozenStocks: 0 }
Em [4]:
var accC = exchanges[2].GetAccount()
accC
Fora[4]: { Saldo: 10 000, FrozenBalance: 0, Stocks: 1, FrozenStocks: 0 }
Em [5]:
var initSumBTC = accA.Balance + accC.Stocks
initSumBTC
Fora[5]: 2 - Não.
Em [6]:
var initSumETH = accA.Stocks + accB.Stocks
initSumETH
Fora[6]: - 11.
Em [7]:
var initSumUSDT = accB.Balance + accC.Balance
initSumUSDT
Fora[7]: 20000
Podemos ver que o número total inicial de BTC é 2, o número total de ETH é 11, e o número total de USDT é 20000.
Em [8]:
var tickerA = exchanges[0].GetTicker()
tickerA
Fora[8]: Hora: 1554831960000, Alto: 0,03396501, Baixo: 0,03396499, Venda: 0,03396501, Comprar: 0,03396499, Último: 0,033965, Volume: 4696,555, Interesse aberto: 0 }
Em [9]:
var tickerB = exchanges[1].GetTicker()
tickerB
Fora[9]: Hora: 1554831960000, Alto: 175.08000001, Baixo: 175,07999999, Venda: 175.08000001, Compra: 175.07999999, Último: 175.08, Volume: 20730.37, Interesse aberto: 0 }
Em [10]:
var tickerC = exchanges[2].GetTicker()
tickerC
Fora[10]: Hora: 1554831960000, Alto: 5161.90000001, Baixo: 5161.89999999, Venda: 5161.90000001, Compra: 5161.89999999, Último: 5161,9. Volume: 2109.9292, Interesse aberto: 0 }
Pode-se ver que o objeto da Exchange A, Exchange B e da transação é o ETH, ou seja, a exchange A/B pode realizar operações de cobertura indireta, mas não pode cobrir diretamente porque as moedas de preços são diferentes.
Suponha que a troca A executa uma operação de compra deexchanges[0].Buy(price, amount)
, e o preço vendido pela contraparte é utilizado como preço de encomenda ao comprar, ou seja,tickerA.Sell
A bolsa B realiza uma operação de venda para cobrança, ou seja,exchanges[1].Sell(price, amount)
, e o preço que a contraparte deseja comprar é utilizado como preço da ordem ao vender, ou seja,tickerB.Buy
Porque a troca A consumiuBTC
quando comprar, e troca B obtido USDT quando vender, troca A precisa substituirUSDT
com BTC para compensar o BTC consumido pela troca A, ou seja, troca C executaexchanges[2].Buy(price, amount)
, e trocaUSDT
comBTC
Para comprar, a troca C precisa ver o preço de venda da contraparte, ou seja,tickerC.Sell
. O preço de compra da troca A deve ser menor que o preço de venda da troca B, então a troca C pode comprar de volta BTC consumido pela troca A com menos USDT. Você ganhará a diferença da quantia USDT.
Então é assim:
Em [11]:
var diffB2A = tickerA.Sell - tickerB.Buy / tickerC.Sell // DiffB2A means that Exchange B sells ETH coins and Exchange A buys ETH coins, which is logically equivalent to the transfer of ETH from Exchange B to Exchange A.
diffB2A
Fora[11]: 0,000047266535449966285
Obviamente, o preço de compra da Bolsa A é superior ao da Bolsa B e da Bolsa C, e a cobertura é obviamente uma perda de dinheiro. A outra direção de cobertura é a mesma. A Exchange A executa a operação de venda de ETH, a Exchange B executa a operação de compra de ETH e a Exchange C vende BTC por USDT. A obtenção da moeda é sempre equilibrada e apenas o USDT aumenta ou diminui (ou seja, a diferença ganha).
Em [12]:
var diffA2B = tickerA.Buy - tickerB.Sell / tickerC.Buy
diffA2B
Fora[12]: 0,000047246531444007644 (em inglês)
Vamos fazer umtickerA.Buy - tickerB.Sell / tickerC.Buy
operação de cobertura para descobrir como cada um dos valores muda.
Em [13]:
var idA = exchanges[0].Sell(tickerA.Buy, 1)
var nowAccA = exchanges[0].GetAccount()
nowAccA // We can see that the handling fee is deducted from the BTC.
Fora[13]: Saldo: 1,0339514, FrigoríficoBalance: 0, Reservas: 9, FrozenStocks:
Em [14]:
var orderA = exchanges[0].GetOrder(idA)
orderA
Fora [1]:
{Id: 1,
Preço: 0.03396499,
Montante: 1,
Transação: 1.
Preço médio: 0.03396499,
Tipo: 1,
Deslocamento: 0,
Situação: 1,
Tipo de contrato:
Em [15]:
var feeRatioA = 0.0004 // The default handling fee for backtesting is 0.2%, i.e. 0.002.
var feeA = orderA.DealAmount * orderA.AvgPrice * feeRatioA // Exchange A trading handling fees, BTC denominated.
feeA
Fora [1]: 0,000013585996
Em [16]:
var idB = exchanges[1].Buy(tickerB.Sell, 1)
var nowAccB = exchanges[1].GetAccount()
nowAccB
Fora [1]: O saldo: 9824.84996798, FrozenBalance: 0, Reservas: 2, FrozenStocks:
Em [17]:
var orderB = exchanges[1].GetOrder(idB)
orderB // We can see that the handling fee is deducted from the USDT.
Fora [1]:
{Id: 1,
Preço: 175.08000001,
Montante: 1,
O montante do acordo é: 1
Preço médio: 175.08000001,
Tipo: 0,
Deslocamento: 0,
Situação:
ContractType:
Em [18]:
var feeRatioB = 0.0004
var feeB = orderB.DealAmount * orderB.AvgPrice * feeRatioB / tickerC.Last // Exchange B handling fees, converted to BTC denomination.
feeB
Fora [1]: 0,000013567097387396117
Em [19]:
var idC = exchanges[2].Sell(tickerC.Buy, nowAccA.Balance - accA.Balance)
var nowAccC = exchanges[2].GetAccount()
nowAccC
Fora [1]: Saldo: 10174,91841463, FrigoríficoBalance: 0, Reservas: 0,9661. FrozenStocks:
Em [20]:
var orderC = exchanges[2].GetOrder(idC)
orderC // We can see that the handling fee is deducted from the USDT.
Fora [1]:
{Id: 1,
Preço: 5161.89999999,
Montante: 0,0339,
O valor da transacção é de 0,0339.
Preço médio: 5161.89999999,
Tipo: 1,
Deslocamento: 0,
Situação:
Tipo de contrato:
Em [21]:
var feeRatioC = 0.0004
var feeC = orderC.DealAmount * orderC.AvgPrice * feeRatioC / tickerC.Last // Exchange C trading handling fees, BTC denominated.
feeC
Fora[21]: 0,000013559999999973732
Calcular a informação total sobre os ativos após cobertura.
Em [22]:
var nowSumBTC = nowAccA.Balance + nowAccC.Stocks
nowSumBTC
Fora[22]: 2.0000514000000003
Em [23]:
var nowSumETH = nowAccA.Stocks + nowAccB.Stocks
nowSumETH
Fora[23]: 11
Em [24]:
var nowSumUSDT = nowAccB.Balance + nowAccC.Balance
nowSumUSDT
Fora[24]: 19999.76838261
Em [25]:
nowSumBTC - initSumBTC
Fora[25]: 0,000051400000000256796
Em [26]:
tickerC.Buy * (nowSumBTC - initSumBTC) // The extra BTC is converted to USDT.
Fora[26]: 0,26532166000081153
Em [27]:
nowSumUSDT + tickerC.Buy * (nowSumBTC - initSumBTC) - initSumUSDT // Profit and loss is calculated based on the changes of the account assets and is denominated in USDT.
Fora[27]: 0,0337042700011807
Em [28]:
(diffA2B - (feeA + feeB + feeC)) * tickerC.Buy // Profit and loss based on price difference, denominated in USDT.
Fora[28]: 0,03372495390449328
Pode-se ver que a diferença de preço durante a cobertura édiffA2B
: 0,000047246531444007644.
A taxa de manipulação para as três coberturas é convertida em BTC como:feeA+feeB+feeC
.
Em [29]:
feeA + feeB + feeC
Fora[29]: 0,00004071309338736985
Pode-se ver que na configuração do backtest, a taxa de manuseio é alterada para"fee":[0.04,0.04]
, ou seja, 0,04%.feeA+feeB+feeC
A diferença de preço entre os dois tipos de cobertura é igual a 0,00004071309338736985, o que é basicamente próximo da diferença de preço diffA2B no momento da cobertura. Finalmente, o lucro e perda calculado é muito pequeno, apenas 0,03372495390449328, e o lucro e perda calculados através da mudança de conta é basicamente o mesmo que o calculado através da diferença de preço. Este documento de pesquisa pode ser usado para calcular a quantidade de diferença que pode ser coberta para a cobertura triangular.