Continuemos a explicar o conteúdo do último capítulo (https://www.fmz.com/bbs-topic/9725).
A terceira função adicionada:
self.balanceAccount = function() {
var account = exchange.GetAccount()
if (!account) {
return
}
self.account = account
var now = new Date().getTime()
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {
self.preCalc = now
var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
}
self.btc = account.Stocks
self.cny = account.Balance
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
var balanced = false
if (self.p < 0.48) {
Log ( \"\" Start Balance \"\", self. P)
self.cny -= 300
if (self.orderBook.Bids.length >0) {
exchange.Buy(self.orderBook.Bids[0].Price + 0.00, 0.01)
exchange.Buy(self.orderBook.Bids[0].Price + 0.01, 0.01)
exchange.Buy(self.orderBook.Bids[0].Price + 0.02, 0.01)
}
} else if (self.p > 0.52) {
Log ( \"\" Start Balance \"\", self. P)
self.btc -= 0.03
if (self.orderBook.Asks.length >0) {
exchange.Sell(self.orderBook.Asks[0].Price - 0.00, 0.01)
exchange.Sell(self.orderBook.Asks[0].Price - 0.01, 0.01)
exchange.Sell(self.orderBook.Asks[0].Price - 0.02, 0.01)
}
}
Sleep(BalanceTimeout)
var orders = exchange.GetOrders()
if (orders) {
for (var i = 0; i < orders.length; i++) {
if (orders[i].Id != self.tradeOrderId) {
exchange.CancelOrder(orders[i].Id)
}
}
}
}
Quando o construtorLeeksReaper ()
construi um objeto, obalanceAccount ()
A função adicionada ao objeto atualiza as informações do ativo da conta armazenadas noself.account
, ou seja, oaccount
Atributo do objeto construído. Calcule o valor da receita e imprima-lo a tempo. Em seguida, de acordo com a última informação do ativo da conta, calcule a relação de saldo da moeda dos pontos (balanço da posição dos pontos), ao desencadear o limiar de deslocamento, feche a posição com uma pequena ordem, para que a moeda (posição) de volta ao estado de equilíbrio. Espere um certo tempo para negociar, depois cancele todos os fabricantes, a próxima rodada de execução da função, verificará o saldo e fará o processamento correspondente novamente.
Vejamos o código desta função sentença por sentença:
Primeiro, a primeira frase.var account = exchange.GetAccount ()
declara uma variável localaccount
e chama a função deexchange.GetAccount
Obter os dados mais recentes da conta corrente e atribuí-lo para a variávelaccount
Então julgue a variável.account
Se a variável for:null
(por exemplo, timeout, rede, interfaces de troca exceção, etc.), ele irá retornar (correspondente aif (!account) {...}
) directamente.
self.account = account
é atribuir a variável localaccount
para oaccount
Atributo do objeto construído para registar as últimas informações da conta no objeto construído.
Var now = new Date().getTime ()
declara uma variável localnow
e chama ogetTime()
atribui um valor à variávelnow
.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)){...}
Determina que se a diferença entre o carimbo horário atual e o carimbo horário registrado da última vez excede o parâmetroCalcNet Interval * 1000
, significa que foi atualizado desde a última vez.CalcNetInterval * 1000
milissegundos (CalcNetInterval
O preço de compra de um exemplar é utilizado para calcular o rendimento, a condição deself.orderBook.Bids.length > 0
Quando a condição de instrução if é acionada, a instrução de nível de dados de profundidade é executada.self.PreCalc = now
é executado para atualizar a variável de carimbo horário da declaração impressa mais recenteself.preCalc
para o carimbo de hora correntenow
O método de cálculo do valor líquido é utilizado nas estatísticas de retorno.var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))
, ou seja, converter a moeda em dinheiro (moeda denominada) de acordo com o preço de compra atual, e depois adicioná-lo ao montante de dinheiro na conta e atribuí-lo à variável local declaradanet
Julgar se o valor líquido total actual é consistente com o valor líquido total registado na última vez:
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
Se não for consistente, isto é,net! = self.preNet
é verdade, atualizar o atributo deself.preNet
utilizado para registar o valor líquido com a variávelnet
Em seguida, imprima o total líquido denet
dados para o gráfico da curva de rendimento do robô da plataforma de negociação FMZ Quant (oLogProfit
Função pode ser consultada no documento FMZ API).
Se a impressão regular dos ganhos não for desencadeada, prossiga com o seguinte processo para registar oaccount.Stocks
(moeda disponível na conta corrente) eaccount.Balance
(moeda disponível na conta corrente) noself.BTC
eself.CNY
. Calcular a escala de deslocamento e registar a atribuição noself.p
.
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
O algoritmo também é muito simples, que é calcular a percentagem do valor corrente da moeda para o valor líquido total da conta.
E quanto a julgar quando acionar o saldo de dinheiro (posição)?
Aqui, eu tomo 50% mais ou menos 2 pontos percentuais como o buffer, e executa o saldo além do buffer, ou seja, se oself.p < 0.48
Se o dinheiro for menor, o preço aumentará 0,01 cada vez a partir da posição de compra na abertura do mercado, e três pequenas ordens serão organizadas.self.p > 0.52
, se a moeda é mais, vender um e liberar pequenos pedidos.Sleep(BalanceTimeout)
durante um determinado período de tempo, de acordo com as definições dos parâmetros.
Var orders = exchange. Get Orders () # Get all current makers, with orders variable
If (orders) { # If the variable orders used to obtain the current order data is not null
for (var i = 0; i < orders.length; I + +) { # Loop through orders and cancel orders one by one
if (orders[i].Id != self.tradeOrderId) {
Exchange. CancelOrder (orders [I]. Id) # Call exchange. CancelOrder to cancel orders based on orders [I]. Id
}
}
}
A quarta função adicionada:
Na parte central da estratégia, aqui vem a jogada principal.self.poll = function(){...}
A estratégia de desenvolvimento sustentável é a lógica principal de toda a estratégia, tal como dissemos no artigo anterior, antes damain()
função começa a executar e entra no infinitowhile
Loop, nós usamosvar reaper = LeeksReaper()
para construir o objeto leeksreaper, e, em seguida, executar a chamada de loop dereaper.poll()
emmain()
function.
Oself.poll
A função começa a executar, fazendo algum trabalho preparatório antes de cada loop.self.numTick++
A redução da taxa de mortalidadeself.updateTrades()
O sistema de gestão de dados de mercado é um sistema de gestão de dados de mercado que atualiza os registos recentes de negociação de mercado e calcula os dados de utilização relevantes.self.updateOrderBook()
O sistema de gestão dos pedidos de serviços de informação e de informação é um sistema de gestão de dados.self.balanceAccount()
verificar o saldo da posição monetária.
Var burstPrice = self. Prices [self. Prices. Length-1] * BurstThresholdPct # Calculate Burst Price
Var bull = false # Declare a bull-marked variable, initially false
Var bear = false # Declare a bear marked variable, initially false
Var tradeAmount = 0 # Declare the transaction amount variable, initially 0
O próximo passo é julgar se o mercado de curto prazo atual é um touro ou um urso.
if (self.numTick > 2 && (
self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -1)) > burstPrice ||
self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -2)) > burstPrice && self.prices[self.prices.length-1] > self.prices[self.prices.length-2]
)) {
bull = true
tradeAmount = self.cny / self.bidPrice * 0.99
} else if (self.numTick > 2 && (
self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -1)) < -burstPrice ||
self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -2)) < -burstPrice && self.prices[self.prices.length-1] < self.prices[self.prices.length-2]
)) {
bear = true
tradeAmount = self.btc
}
Lembras-te doself.updateOrderBook()
função do artigo anterior onde usamos um algoritmo média ponderada para construir um tempo ordenadoprices
Três novas funções:_.min
, _.max
, eslice
são utilizadas no código e são fáceis de compreender.
· _. min
: A função é encontrar o valor mínimo na matriz de parâmetros.
· _.max
: A função é encontrar o valor máximo na matriz de parâmetros.
· slice
A função é uma função membro daJavaScript
É usado para retornar uma parte da matriz de acordo com o índice. Por exemplo:
function main() {
// index .. -8 -7 -6 -5 -4 -3 -2 -1
var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Log (arr. Slice (-5, -1)) // it will intercept the elements from 4 to 1 and return a new array: [4,3,2,1]
}
As condições para julgar um mercado de baixa ou alta são:
· Oself.numTick > 2
Deve ser verdadeiro, ou seja, quando uma nova rodada de preço de detecção ocorre, deve ser desencadeada após pelo menos três rodadas de detecção, de modo a evitar desencadear no início.
· A diferença entre os últimos dados doself.prices
A sequência de preços, isto é, os dados mais recentes, e o preço máximo ou mínimo no intervalo anterior no intervalo de preços de mercado.self.prices
Array deve exceder o preço de ruptura deburstPrice
.
Se todas as condições forem verdadeiras, marquebull
oubear
como verdadeiro, e atribuir um valor para a variáveltradeAmount
para planear a transacção do Stud.
Em seguida, de acordo com oself.vol
A taxa de crescimento da populaçãoself.updateTrades()
Função, oBurstThresholdVol
O parâmetro determina se a intensidade da transacção deve ser reduzida (reduzir o volume de transacções planeado).
if (self.vol < BurstThresholdVol) {
TradeAmount * = self. Vol/BurstThresholdVol //Reduce the planned volume by self. Vol/BurstThresholdVol times of the previous volume
}
if (self.numTick < 5) {
TradeAmount * = 0.8 // reduced to 80% of the plan
}
If (self. NumTick < 10) { // reduce to 80% of the plan
tradeAmount *= 0.8
}
Em seguida, julgue se o sinal de negociação e o volume cumprem os requisitos:
If ( (!Bull && !Bear) | | tradeAmount < MinStock) { # If it is not a bull market and not a bear market, or the amount tradeAmount planned to trade is less than the minimum trading volume MinStock set by the parameter, the poll function returns without trading operations directly
return
}
Após a sentença acima, executarvar tradePrice = bull ? self.bidPrice: self.askPrice
Estabelece o preço da transacção em função de se tratar de um mercado de baixa ou de alta, e atribui o valor com o preço correspondente da fatura.
Por fim, umawhile
A única condição de parada do ciclo é que o volume de negociação planeado detradeAmount > = MinStock
É inferior ao volume mínimo de negociação.
No loop, a ordem é executada de acordo com o estado atual do mercado.orderId
. Sleep(200)
O circuito determina então se oorderId
é verdade (se a ordem falhar, o ID da ordem não será devolvido, e a condição if não será acionada).self.tradeOrderId
.
Declarar uma variávelorder
utilizado para armazenar dados de encomendas, com um valor inicial denull
. Em seguida, os dados de ordem do ID são obtidos em um loop, e julgar se a ordem é o estado do fabricante, se assim for, a ordem do ID é cancelada, e se não, o loop de detecção é encerrado.
Var order = null // Declare a variable to hold the order data
While (true) { // a while loop
Order = exchange. GetOrder (orderId) // Call GetOrder to query the order data whose order ID is orderId
If (order) { // If the order data is queried and the query fails and the order is null, the current if condition will not be triggered
If (order. Status = = ORDER _ STATE _ PENDING) { // Judge whether the order status is maker
Exchange. CancelOrder (orderId) // If the order is maker, cancel the order
Sleep(200)
} else { // otherwise execute break to end the current while loop
break
}
}
}
Em seguida, realiza-se o seguinte processo:
Self. TradeOrderId = 0 // Reset self. TradeOrderId.
TradeAmount-= order. DealAmount // Update tradeAmount, subtract the quantity of the order on the bill of lading that has been completed
TradeAmount * = 0.9 //Decrease the order amount
If (order. Status = = ORDER _ STATE _ CANCELED) { // if the order is already cancelled
Self. UpdateOrderBook () // Update data such as order book
While (bull & & self. BidPrice-tradePrice > 0.1) { // In a bull market, if the updated bill of lading price exceeds the current trading price by 0.1, the trading amount will be reduced and the trading price will be adjusted slightly
tradeAmount *= 0.99
tradePrice += 0.1
}
While (bear & & self. AskPrice-tradePrice < -0.1) { // In a bear market, if the updated bill of lading price exceeds the current trading price by 0.1, the trading amount will be reduced and the trading price will be adjusted slightly
tradeAmount *= 0.99
tradePrice -= 0.1
}
}
Quando o processo do programa termina do loop dewhile (tradeAmount > = MinStock){...}
, indica que a execução deste processo de transacção de rajada de preços está concluída.
Executar oself.numTick = 0
, isto é, redefinir oself.numTick
para 0.
OLeeksReaper()
Construtor retorna oself
Objeto no final da execução, isto é, quandovar reaper = LeeksReaper()
, é devolvido aoreaper
.
Até agora, analisámos como oLeeksReaper()
Eu acredito que você terá uma compreensão clara deste processo de algoritmo de estratégia de alta frequência depois de ler este artigo.