이전 기사에서는 거래의 원리와 재검토에 대해 설명했습니다.https://www.fmz.com/digest-topic/10457▲ 여기에 FMZ 플랫폼에 기반한 실용적인 소스 코드가 제시되어 있으며, 전략은 비교적 간단하고 명확하며 초보자 학습에 적합하다. ▲ FMZ 플랫폼은 최근 일부 API를 업그레이드하여 멀티 트레이드 친화적인 정책을 제시했다. ▲ 이 문서에서는 이 정책의 자바스크립트 소스 코드가 상세히 설명된다. ▲ 정책은 단지 100줄이지만 완전한 정책이 필요한 모든 측면을 포함하고 있다.https://www.fmz.com/strategy/456143이 글은 이쪽에서 직접 복사할 수 있습니다.
FMZ 플랫폼에 익숙하지 않은 분들은 이 튜토리얼을 읽어보시기 바랍니다.https://www.fmz.com/bbs-topic/4145◎ 플랫폼의 기본 기능과 로봇을 처음부터 어떻게 배치할 수 있는지에 대한 자세한 설명.
아래는 가장 간단한 전략 프레임워크이며, 주요 기능은 입문이다. 죽음의 순환을 보장하는 전략은 지속적으로 실행되며, 작은 휴면 시간을 추가하여 접근 빈도가 거래소 한계를 초과하는 것을 피합니다.
function main(){
while(true){
//策略内容
Sleep(Interval * 1000) //Sleep
}
}
로봇은 오류, 파라미터 업데이트, 정책 업데이트 등 다양한 이유로 반복적으로 다시 시작하여 다음 시작에 사용할 수 있는 데이터를 저장해야 합니다. 여기서 초기 권한 이익을 계산하기 위해 저장하는 방법을 보여줍니다.
let init_eq = 0 //定义初始权益
if(!_G('init_eq')){ //如果没有储存_G('init_eq')返回null
init_eq = total_eq
_G('init_eq', total_eq) //由于没有储存,初始权益为当前权益,并在这里储存
}else{
init_eq = _G('init_eq') //如果储存,读取初始权益的值
}
API를 통해 포지션, 시장 등의 데이터를 획득할 때, 여러 가지 이유로 오류가 발생할 수 있다. 이는 직접적으로 데이터를 호출하면 정책 오류가 중단될 수 있기 때문에 오류 허용 장치가 필요합니다. _C () 함수는 오류가 발생하면 올바른 데이터를 반환할 때까지 자동으로 다시 시도합니다. 또는 반환 후 사용 가능한 데이터를 검사합니다.
let pos = _C(exchange.GetPosition, pair)
let ticker_A = exchange.GetTicker(pair_a)
let ticker_B = exchange.GetTicker(pair_b)
if(!ticker_A || !ticker_B){
continue //如果数据不可用,就跳出这次循环
}
GetPosition, GetTicker, GetRecords와 같은 함수는 거래 쌍의 매개 변수를 추가하여 교환 결합 트랜잭션 쌍을 설정하지 않고 해당 데이터에 액세스 할 수 있습니다. 이는 여러 거래와 전략의 호환성을 매우 편리하게합니다. 구체적인 업그레이드 내용은 다음 문서를 참조하십시오:https://www.fmz.com/digest-topic/10451물론, 최신 호스트가 필요합니다. 만약 당신의 호스트가 너무 오래되면 업그레이드해야 합니다.
FMZ의 API 문서, 디뷰팅 도구 및 시장에서 자주 사용되는 AI 대화 도구로 질문을 해결할 수 있습니다.
function GetPosition(pair){
let pos = _C(exchange.GetPosition, pair)
if(pos.length == 0){ //返回为空代表没有持仓
return {amount:0, price:0, profit:0}
}else if(pos.length > 1){ //策略要设置为单向持仓模式
throw '不支持双向持仓'
}else{ //为了方便,多仓持仓量为正,空仓持仓量为负
return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit}
}
}
function GetRatio(){
let kline_A = exchange.GetRecords(Pair_A+"_"+Quote+".swap", 60*60, N) //小时K线
let kline_B = exchange.GetRecords(Pair_B+"_"+Quote+".swap", 60*60, N)
let total = 0
for(let i= Math.min(kline_A.length,kline_B.length)-1; i >= 0; i--){ //反过来计算,避免K线长度不够
total += kline_A[i].Close / kline_B[i].Close
}
return total / Math.min(kline_A.length,kline_B.length)
}
function GetAccount(){
let account = _C(exchange.GetAccount)
let total_eq = 0
if(exchange.GetName == 'Futures_OKCoin'){ //由于这里的API并不兼容,目前仅OKX期货交易所获取到总权益
total_eq = account.Info.data[0].totalEq //其他交易所的宗权益Info中也包含,可以自己对着交易所API文档找找
}else{
total_eq = account.Balance //其它交易所暂时使用可用余额,会造成计算收益错误,但不影响策略使用
}
let init_eq = 0
if(!_G('init_eq')){
init_eq = total_eq
_G('init_eq', total_eq)
}else{
init_eq = _G('init_eq')
}
LogProfit(total_eq - init_eq)
return total_eq
}
function main(){
var precision = exchange.GetMarkets() //这里获取精度
var last_get_ratio_time = Date.now()
var ratio = GetRatio()
var total_eq = GetAccount()
while(true){
let start_loop_time = Date.now()
if(Date.now() - last_get_ratio_time > 10*60*1000){ //每10分钟更新下均价和账户信息
ratio = GetRatio()
total_eq = GetAccount()
last_get_ratio_time = Date.now()
}
let pair_a = Pair_A+"_"+Quote+".swap" //交易对的设置形如BTC_USDT.swap
let pair_b = Pair_B+"_"+Quote+".swap"
let CtVal_a = "CtVal" in precision[pair_a] ? precision[pair_a].CtVal : 1 //有的交易所用张来代表数量,如一张代表0.01个币,因此需要换算下
let CtVal_b = "CtVal" in precision[pair_b] ? precision[pair_b].CtVal : 1 //不含这个字段的不用张
let position_A = GetPosition(pair_a)
let position_B = GetPosition(pair_b)
let ticker_A = exchange.GetTicker(pair_a)
let ticker_B = exchange.GetTicker(pair_b)
if(!ticker_A || !ticker_B){ //如果返回数据异常,跳出这次循环
continue
}
let diff = (ticker_A.Last / ticker_B.Last - ratio) / ratio //计算偏离的比例
let aim_value = - Trade_Value * diff / Pct //目标持有的仓位
let id_A = null
let id_B = null
//以下是具体的开仓逻辑
if( -aim_value + position_A.amount*CtVal_a*ticker_A.Last > Trade_Value && position_A.amount*CtVal_a*ticker_A.Last > -Max_Value){
id_A = exchange.CreateOrder(pair_a, "sell", ticker_A.Buy, _N(Ice_Value / (ticker_A.Buy * CtVal_a), precision[pair_a].AmountPrecision))
}
if( -aim_value - position_B.amount*CtVal_b*ticker_B.Last > Trade_Value && position_B.amount*CtVal_b*ticker_B.Last < Max_Value){
id_B = exchange.CreateOrder(pair_b, "buy", ticker_B.Sell, _N(Ice_Value / (ticker_B.Sell * CtVal_b), precision[pair_b].AmountPrecision))
}
if( aim_value - position_A.amount*CtVal_a*ticker_A.Last > Trade_Value && position_A.amount*CtVal_a*ticker_A.Last < Max_Value){
id_A = exchange.CreateOrder(pair_a, "buy", ticker_A.Sell, _N(Ice_Value / (ticker_A.Sell * CtVal_a), precision[pair_a].AmountPrecision))
}
if( aim_value + position_B.amount*CtVal_b*ticker_B.Last > Trade_Value && position_B.amount*CtVal_b*ticker_B.Last > -Max_Value){
id_B = exchange.CreateOrder(pair_b, "sell", ticker_B.Buy, _N(Ice_Value / (ticker_B.Buy * CtVal_b), precision[pair_b].AmountPrecision))
}
if(id_A){
exchange.CancelOrder(id_A) //这里直接撤销
}
if(id_B){
exchange.CancelOrder(id_B)
}
let table = {
type: "table",
title: "交易信息",
cols: ["初始权益", "当前权益", Pair_A+"仓位", Pair_B+"仓位", Pair_A+"持仓价", Pair_B+"持仓价", Pair_A+"收益", Pair_B+"收益", Pair_A+"价格", Pair_B+"价格", "当前比价", "平均比价", "偏离均价", "循环延时"],
rows: [[_N(_G('init_eq'),2), _N(total_eq,2), _N(position_A.amount*CtVal_a*ticker_A.Last, 1), _N(position_B.amount*CtVal_b*ticker_B.Last,1),
_N(position_A.price, precision[pair_a].PircePrecision), _N(position_B.price, precision[pair_b].PircePrecision),
_N(position_A.profit, 1), _N(position_B.profit, 1), ticker_A.Last, ticker_B.Last,
_N(ticker_A.Last / ticker_B.Last,6), _N(ratio, 6), _N(diff, 4), (Date.now() - start_loop_time)+"ms"
]]
}
LogStatus("`" + JSON.stringify(table) + "`") //这个函数会在机器人页面显示包含以上信息的表格
Sleep(Interval * 1000) //休眠时间为ms
}
}
시디안슈아안녕하세요, 재검토 교환.GetMarkets (() 단 하나의 거래 쌍의 데이터를 얻을 수 있습니다.
77924998파이썬 버전이 있나요?
콩 888/upload/asset/21c799a2c667c13fcb0bd.png
턱은 약간
발명가들의 수량화 - 작은 꿈리테스트는 현재 GetMarkets 기능을 지원하지 않습니다. 조금 더 기다려주세요.
차오장최신 호스트로 업그레이드