O número de estratégias de código aberto no TradingView é grande. É uma pena que tantas estratégias, ideias e indicadores excelentes não possam ser usados em bot real. Vendo isso, a FMZ, que está comprometida em popularizar a tecnologia de negociação quantitativa para muitos comerciantes, naturalmente não pode suprimir esse desejo de resolver o problema!
Esta partilha de experiências é absolutamente a oferecer!
Então, depois de caminhar pelo mundo da programação e desenvolvimento de código, passando por 9 * 9 = 81 poços, sobrevivendo a inúmeras noites sem dormir, e empilhando uma montanha de latas vazias de Red Bull no canto.
Quando se trata da linguagem Pine, eu só recentemente aprendi sozinho. Mas para ser honesto, a linguagem Pine para negociação quantitativa é realmente fácil de usar e fácil de aprender. Deixe-me escrever uma estratégia de rede para você:
/*backtest
start: 2021-06-01 00:00:00
end: 2022-05-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
args: [["v_input_float_1",500],["v_input_string_1",2],["v_input_float_2",0.01],["v_input_int_1",20],["v_input_int_2",500],["RunMode",1,358374],["MinStock",0.001,358374]]
*/
strategy(overlay=true)
varip beginPrice = 0
var spacing = input.float(-1, title="Spacing prices")
var dir = input.string("long", title="Directions", options = ["long", "short", "both"])
var amount = input.float(-1, title="Order quantity")
var numbers = input.int(-1, title="Number of grids")
var profit = input.int(-1, title="Profit spreads") / syminfo.mintick
if spacing == -1 and amount == -1 and numbers == -1 and profit == -1
runtime.error("Parameter errors")
if not barstate.ishistory and beginPrice == 0
beginPrice := close
findTradeId(id) =>
ret = "notFound"
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == id
ret := strategy.opentrades.entry_id(i)
ret
// Real-time K-line stage
if not barstate.ishistory
// Retrieve grid
for i = 1 to numbers
// Going long
direction = dir == "both" ? "long" : dir
plot(beginPrice-i*spacing, direction+str.tostring(i), color.green)
if direction == "long" and beginPrice-i*spacing > 0 and beginPrice-i*spacing < close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.long, qty=amount, limit=beginPrice-i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
// Going short
direction := dir == "both" ? "short" : dir
plot(beginPrice+i*spacing, direction+str.tostring(i), color.red)
if direction == "short" and beginPrice+i*spacing > close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.short, qty=amount, limit=beginPrice+i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
O FMZ
É claro que esta estratégia é uma estratégia de grade, que também tem falhas, e não é uma máquina de impressão de dinheiro que sempre ganha. A chave depende do uso e parâmetros. Vamos nos concentrar mais em como escrever estratégias facilmente para implementar nossa própria lógica de negociação, e ganhar dinheiro escrevendo estratégias e negociando nós mesmos. É tão legal não pedir ajuda!
Eu vou explicar a todos, o código é simples e fácil de entender, com uma linguagem tão fácil de aprender e usar Pine, se você ainda não sabe escrever uma estratégia, então eu vou... dizer-lhe em detalhes!
O conteúdo do/*backtest
e*/
no início está o código de configuração de backtest de FMZ. Esta é a função de FMZ, não o conteúdo da linguagem Pine. Claro, você pode deixar esta parte fora, e você vai clicar no controle de parâmetros manualmente para definir a configuração de backtest e parâmetros durante o backtesting.
/*backtest
start: 2021-06-01 00:00:00
end: 2022-05-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
args: [["v_input_float_1",500],["v_input_string_1",2],["v_input_float_2",0.01],["v_input_int_1",20],["v_input_int_2",500],["RunMode",1,358374],["MinStock",0.001,358374]]
*/
O próximo código:
strategy(overlay=true)
varip beginPrice = 0
var spacing = input.float(-1, title="Spacing prices")
var dir = input.string("long", title="Directions", options = ["long", "short", "both"])
var amount = input.float(-1, title="Order quantity")
var numbers = input.int(-1, title="Number of grids")
var profit = input.int(-1, title="Profit points") / syminfo.mintick
strategy(overlay=true)
: É usado para definir algumas opções do script, overlay=true, que é atribuir valor verdadeiro ao parâmetrooverlay
, de modo que ao desenhar o gráfico, ele é desenhado no gráfico principal (K-line chart é o gráfico principal, pode ser entendido tão simplesmente).varip beginPrice = 0
: Uma variável beginPrice é declarada com a palavra-chave varip com um valor inicial de 0, que é utilizado como preço inicial para a grade.var spacing = input.float(-1, title="Spacing prices")
: Configure um parâmetro de estratégia, o nome do parâmetro é var dir = input.string("long", title="Directions", options = ["long", "short", "both"])
: Configure um parâmetro de estratégia chamado var amount = input.float(-1, title="Order quantity")
: Definir um parâmetro para controlar o volume de transacções em cada transacção de ponto de rede.var numbers = input.int(-1, title="Number of grids")
: o número de pontos da grade, definindo 20 é 20 pontos da grade em uma direção.var profit = input.int(-1, title="Profit spreads") / syminfo.mintick
: Definir um parâmetro para controlar a margem de lucro de cada posição de ponto de rede antes de fechar a posição.Em seguida, olhem para o código:
if spacing == -1 and amount == -1 and numbers == -1 and profit == -1
runtime.error("Parameter errors")
Significa que se quaisquer parâmetros como espaçamento, quantidade, números e lucro não forem definidos, o padrão é -1, e a estratégia vai parar (você não pode operar cegamente sem definir parâmetros)
Vamos, vamos!
if not barstate.ishistory and beginPrice == 0
beginPrice := close
O que isso significa aqui é que quando a estratégia está no estágio de linha K em tempo real e startPrice == 0, mude o valor de startPrice para o último preço atual. Pode-se entender que quando a estratégia está sendo executada oficialmente, o preço atual inicial é o preço inicial da grade. Como o script tem um estágio histórico de BAR da linha K, a estratégia executará a lógica uma vez no estágio histórico de BAR, e definitivamente não faz sentido organizar a grade no BAR histórico.
Qual é a fase histórica do BAR?
Para dar um exemplo simples, no momento atual A, a estratégia começa a ser executada, e a estratégia obtém dados com 100 K-line BARs. Com o passar do tempo, 100 BARs se tornarão 101, 102...N. Quando começa a ser executado a partir do momento A, o 101o BAR é o estágio da linha K em tempo real, e este tempo é os dados mais recentes em tempo real.
barstate.ishistory
esta é uma variável embutida na linguagem Pine,barstate.ishistory
é verdade se o BAR atual é um BAR histórico, e falso se não for um BAR histórico.
Em seguida, uma função é criada
findTradeId(id) =>
ret = "notFound"
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == id
ret := strategy.opentrades.entry_id(i)
ret
O papel desta função é descobrir se uma determinada id existe em todas as ordens que atualmente abriram uma posição. Se houver uma chamada da função findTradeId, ela retornará a ID da ordem existente (note que esta ID não é a ID da ordem da bolsa, é o nome dado à ordem pela estratégia ou entendido como um rótulo), se não existir, a cadeia
O próximo passo é iniciar a folha da grade:
// Real-time K-line stage
if not barstate.ishistory
// Retrieve grid
for i = 1 to numbers
// Going long
direction = dir == "both" ? "long" : dir
plot(beginPrice-i*spacing, direction+str.tostring(i), color.green)
if direction == "long" and beginPrice-i*spacing > 0 and beginPrice-i*spacing < close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.long, qty=amount, limit=beginPrice-i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
// Going short
direction := dir == "both" ? "short" : dir
plot(beginPrice+i*spacing, direction+str.tostring(i), color.red)
if direction == "short" and beginPrice+i*spacing > close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.short, qty=amount, limit=beginPrice+i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
O loop for é usado, e o número de loops é determinado de acordo com o valor do parâmetro números, ou seja, o número correspondente de ordens são organizadas. Defina a direção de acordo com o parâmetro dir. Use a função findTradeId para descobrir se a ordem do rótulo na posição da grade atual foi aberta, e apenas coloque a ordem planejada se não houver posição aberta (se a posição estiver aberta, não pode ser repetida). Para colocar uma ordem, use a função strategy.order para especificar o parâmetro limite como uma ordem planejada. Coloque a ordem de fechamento correspondente enquanto coloca a ordem planejada. A ordem de fechamento usa ostrategy.exitFunção, especifica o parâmetro de lucro e especifica os pontos de lucro.
Olhando para a curva de lucro, podemos ver que a rede também é arriscada. Não é uma vitória garantida. É apenas que o risco de expandir a rede em grande escala é um pouco menor.
Bem, se não sabes escrever uma estratégia numa linguagem tão fácil de aprender e usar, então eu...