No artigo anterior, explicamos a análise lógica de transações de uma estratégia de rede simples, e neste artigo, continuamos para concluir o projeto da estratégia de ensino.
Análise de lógica de transações No artigo anterior, dissemos que basta percorrer cada linha de rede da rede, julgar o preço atual e atravessar a linha de rede para desencadear a ação de negociação. Mas, na verdade, há muitos detalhes lógicos, muitas vezes não entendem a estratégia.
Primeiro, o primeiro detalhe que vamos considerar é o design deste lado da grade infinita.createNet
Então? Esta função gera uma estrutura de dados de rede com um número finito de linhas de rede. E se, quando a estratégia for executada, o preço ultrapassar os limites da estrutura de dados de rede (além da linha de rede mais alta e mais baixa)?
Assim, primeiro precisamos adicionar um mecanismo de extensão à estrutura de dados da grade.
Começar a escrever a política principal função, que é o código que a política começa a executar.
var diff = 50 // 全局变量,网格间距,可以设计成参数,方便讲解,我们把这个参数写死在代码里。
function main() {
// 实盘开始运行后,从这里开始执行策略代码
var ticker = _C(exchange.GetTicker) // 获取市场最新的行情数据ticker,ticker这个数据的结构参看FMZ API文档:https://www.fmz.com/api#ticker
var net = createNet(ticker.Last, diff) // 我们上篇设计的初始构造网格数据结构的函数,这里构造一个网格数据结构net
while (true) { // 然后程序逻辑就进入了这个while死循环,策略执行到此将不停的循环执行这里{}符号之内的代码
ticker = _C(exchange.GetTicker) // 死循环代码部分的第一行,获取最新的行情数据,更新给ticker变量
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// 还有其它代码...
}
}
Para que a estrutura de dados da grade possa ser estendida é este código (selecionado do código acima):
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) { // 如果价格超过网格最高价格的网格线
net.push({ // 就在网格最高价格的网格线之后加入一个新的网格线
buy : false, // 初始化卖出标记
sell : false, // 初始化买入标记
price : net[net.length - 1].price + diff, // 在之前最高价格的基础上再加一个网格间距
})
}
while (ticker.Last <= net[0].price) { // 如果价格低于网格最低价格的网格线
var price = net[0].price - diff // 区别于向上添加,要注意向下添加新网格线的价格不能小于等于0,所以这里要判断
if (price <= 0) { // 小于等于0就不添加了,跳出这层循环
break
}
net.unshift({ // 就在网格最低价格的网格线之前添加一个新的网格线
buy : false,
sell : false,
price : price,
})
}
A seguir, é preciso considerar como concretizar o gatilho de transação.
var diff = 50
var amount = 0.002 // 增加一个全局变量,也可以设计成参数,当然为了简便讲解,我们也写死在策略代码,
// 这个参数控制每次网格线上触发交易时的交易量
function main() {
var ticker = _C(exchange.GetTicker)
var net = createNet(ticker.Last, diff)
var preTicker = ticker // 在主循环(死循环)开始前,设置一个变量,记录上一次的行情数据
while (true) {
ticker = _C(exchange.GetTicker)
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// 检索网格
for (var i = 0 ; i < net.length ; i++) { // 遍历网格数据结构中的所有网格线
var p = net[i]
if (preTicker.Last < p.price && ticker.Last > p.price) { // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
if (i != 0) {
var downP = net[i - 1]
if (downP.buy) {
exchange.Sell(-1, amount, ticker)
downP.buy = false
p.sell = false
continue
}
}
if (!p.sell && !p.buy) {
exchange.Sell(-1, amount, ticker)
p.sell = true
}
} else if (preTicker.Last > p.price && ticker.Last < p.price) { // 下穿,买入
if (i != net.length - 1) {
var upP = net[i + 1]
if (upP.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
upP.sell = false
p.buy = false
continue
}
}
if (!p.buy && !p.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
p.buy = true
}
}
}
preTicker = ticker // 把当前的行情数据记录在preTicker中,在下一次循环中,作为“上一次”行情数据和最新的对比,判断上穿下穿
Sleep(500)
}
}
O que você pode ver:
preTicker.Last < p.price && ticker.Last > p.price
preTicker.Last > p.price && ticker.Last < p.price
O que é o que nós dissemos no artigo anterior:
A passagem para cima e para baixo é apenas o primeiro passo para determinar se uma transação pode ser feita, e também para determinar a marcação nos dados da grade.
Se for usado, o preço é inferior ao preço da linha de grelha atual e a marca de compra da linha de grelha mais recente. Se o valor da marca de compra for verdadeiro, indica que a linha de grelha anterior foi comprada, reinicie a marca de compra da linha anterior para falsa e reinicie a marca de venda da linha de grelha atual para falsa.
Depois de julgar as condições, se não houver gatilho, continuar a julgar, se a marca de compra/venda na rede atual for falsa, significa que a rede atual pode ser negociada.
A lógica de processamento é a mesma (deixe para os novatos pensarem).
Para ver alguns dados quando eles são reexaminados, escrever uma função.showTbl
Mostrar dados.
function showTbl(arr) {
var tbl = {
type : "table",
title : "网格",
cols : ["网格信息"],
rows : []
}
var arrReverse = arr.slice(0).reverse()
_.each(arrReverse, function(ele) {
var color = ""
if (ele.buy) {
color = "#FF0000"
} else if (ele.sell) {
color = "#00FF00"
}
tbl.rows.push([JSON.stringify(ele) + color])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}
O código da estratégia completa:
/*backtest
start: 2021-04-01 22:00:00
end: 2021-05-22 00:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"OKEX","currency":"ETH_USDT","balance":100000}]
*/
var diff = 50
var amount = 0.002
function createNet(begin, diff) {
var oneSideNums = 10
var up = []
var down = []
for (var i = 0 ; i < oneSideNums ; i++) {
var upObj = {
buy : false,
sell : false,
price : begin + diff / 2 + i * diff,
}
up.push(upObj)
var j = (oneSideNums - 1) - i
var downObj = {
buy : false,
sell : false,
price : begin - diff / 2 - j * diff,
}
if (downObj.price <= 0) { // 价格不能小于等于0
continue
}
down.push(downObj)
}
return down.concat(up)
}
function showTbl(arr) {
var tbl = {
type : "table",
title : "网格",
cols : ["网格信息"],
rows : []
}
var arrReverse = arr.slice(0).reverse()
_.each(arrReverse, function(ele) {
var color = ""
if (ele.buy) {
color = "#FF0000"
} else if (ele.sell) {
color = "#00FF00"
}
tbl.rows.push([JSON.stringify(ele) + color])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}
function main() {
var ticker = _C(exchange.GetTicker)
var net = createNet(ticker.Last, diff)
var preTicker = ticker
while (true) {
ticker = _C(exchange.GetTicker)
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// 检索网格
for (var i = 0 ; i < net.length ; i++) {
var p = net[i]
if (preTicker.Last < p.price && ticker.Last > p.price) { // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
if (i != 0) {
var downP = net[i - 1]
if (downP.buy) {
exchange.Sell(-1, amount, ticker)
downP.buy = false
p.sell = false
continue
}
}
if (!p.sell && !p.buy) {
exchange.Sell(-1, amount, ticker)
p.sell = true
}
} else if (preTicker.Last > p.price && ticker.Last < p.price) { // 下穿,买入
if (i != net.length - 1) {
var upP = net[i + 1]
if (upP.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
upP.sell = false
p.buy = false
continue
}
}
if (!p.buy && !p.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
p.buy = true
}
}
}
showTbl(net)
preTicker = ticker
Sleep(500)
}
}
A estratégia é revisada:
Pode-se ver as características da estratégia da rede, quando se encontra com um mercado em tendência, haverá grandes prejuízos, e os ganhos só se recuperam após a convulsão do setor. Portanto, a estratégia de grelha não é isenta de riscos, a estratégia de mercado de ações ainda pode ser muito difícil, enquanto a estratégia de contrato de futuros é mais arriscada e precisa de uma configuração muito conservadora dos parâmetros da rede.
Husr12345É a linguagem C++.
Tony233Eu acho que há uma falha de lógica aqui, não deveria ser quando você se veste e vende apenas para percorrer uma linha de rede acima do preço atual? Também há exchange.Sell ((-1, amount, ticker) como esta função é diferente do documento API, eu vi que o documento API diz exchange.Sell ((Price, Amount), por que você tem três parâmetros, não entendo, é muito complexo, eu também estou louco
Tony233É difícil.
- O quê?Quando o preço sobe e desce, exchange.Buy ((-1, amount * ticker.Last, ticker), amount * ticker.Last é uma curiosidade, por que não vender?
CYZWXA Comissão considerou que o auxílio não é suficiente para reduzir o risco de prejuízo. last_tick = [] linha = [] Grade_buy_list = [] def preço líquido ((current_price): linha global Imprimir (preço atual) linha = [preço agora*(1+0,003*i) para i no intervalo ((-1000,1000) ] Registo (línea) - Não. def ontick ((): Global last_tick linha global lista global de rede conta = troca.GetAccount ((() Ticker = troca.GetTicker ((() last_tick.append ((ticker['Last']) se len ((último_tick) == 1:retorno Elif len ((last_tick) == 100:del last_tick[1] para i na linha ((len))): se last_tick[-1] > linha[i] e last_tick[-2] < linha[i] e len(grid_buy_list)!= 0 e i > min(grid_buy_list) e conta['Stocks'] >= 0,001: troca.Venda ((último_tick[-1],0.01) Del grid_buy_list[grid_buy_list.index(min(grid_buy_list))] Registo (exchange.GetAccount) elif last_tick[-1] < linha[i] e last_tick[-2] > linha[i] e i não em grid_buy_list: troca.Comprar ((último_tick[-1],0.01) grid_buy_list.append (i) Registo (exchange.GetAccount) def main ((): Não, não, não, não. Registo (exchange.GetAccount) enquanto (Verdadeiro): em tick ((() Dormir ((1000)
CYZWXAfinal, o que eu quero dizer é que, se você quiser comprar novamente, é como se tivesse escrito uma versão para o Python.
Inventor quantificado - sonho pequenoA estratégia é a linguagem JavaScript.
Tony233O contrato de permanência no texto não é um contrato futuro?
Inventor quantificado - sonho pequenoOs futuros são os números de contratos, os pagamentos são os valores do preço de mercado no momento; os pagamentos são os números de moedas no momento.
Tony233O que você quer dizer com isso é que você precisa de uma interface de sub-ordens para suportar o preço do mercado (o tipo de sub-ordem é o pagamento, o parâmetro do sub-quadro é o valor unitário da moeda) e o parâmetro do mercado de moeda digital é o número de contratos.
Tony233Oh, eu entendo.
Inventor quantificado - sonho pequenoA função de API do FMZ pode gerar funções de log output, tais como: Log ((...) ; exchange.Buy ((Price, Amount) ; exchange.CancelOrder ((Id)); etc. com alguns parâmetros de saída conexos após os parâmetros necessários.