功能
合约网格交易 同时通过做空做多来进行差价套利 由于双向策略爆仓几率很小
回测数据
2000u半年翻2倍 收益很明显,无论大涨还是大跌都能扛得住
维护
持续优化
/*backtest start: 2021-01-01 00:00:00 end: 2021-06-21 23:59:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","balance":2000}] */ // 首次买入 let FIRST_BUY = true; // 已存在买涨订单 let MANY_BUYING = false; // 已存在做空订单 let SHORT_BUYING = false; // 买涨订单创建时间 let MANY_BUY_TIME = null; // 做空订单创建时间 let SHORT_BUY_TIME = null; // 买涨空仓时间 let MANY_EMPTY_STEP_TIME = null; // 做空空仓时间 let SHORT_EMPTY_STEP_TIME = null; // 校验空仓时间 let CHECK_TIME = null; let QUANTITY = [0.001, 0.002, 0.004, 0.008, 0.016, 0.032, 0.064]; // 下次购买价格(多仓) let MANY_NEXT_BUY_PRICE = 0; // 下次购买价格(空仓) let SHORT_NEXT_BUY_PRICE = 0; // 当前仓位(多仓) let MANY_STEP = 0; // 当前仓位(空仓) let SHORT_STEP = 0; // 止盈比率 let PROFIT_RATIO = 1; // 补仓比率 let DOUBLE_THROW_RATIO = 1.5; // 卖出后下次购买金额下浮比率 let BUY_PRICE_RATIO = 1; // 交易订单列表(多仓) let MANY_ORDER_LIST = []; // 交易订单列表(空仓) let SHORT_ORDER_LIST = []; function getManyQuantity() { if (MANY_STEP < QUANTITY.length) { return QUANTITY[MANY_STEP] } return QUANTITY[0] } function getShortQuantity() { if (SHORT_STEP < QUANTITY.length) { return QUANTITY[SHORT_STEP] } return QUANTITY[0] } function firstManyBuy(ticker) { if (MANY_BUYING) { return } exchange.SetDirection("buy") let orderId = exchange.Buy(ticker.Last, getManyQuantity()) if (!orderId) { return } MANY_BUYING = true while (true) { exchange.SetDirection("buy") let order = exchange.GetOrder(orderId) if (null === order) { continue } if (1 === order.Status || 2 === order.Status) { MANY_NEXT_BUY_PRICE = order.Price * ((100 - DOUBLE_THROW_RATIO) / 100) MANY_STEP = MANY_STEP + 1 MANY_BUYING = false MANY_EMPTY_STEP_TIME = null let sellPrice = order.Price * ((100 + PROFIT_RATIO) / 100) MANY_ORDER_LIST.push({ buyPrice: order.Price, sellPrice: sellPrice, quantity: order.Amount, isSell: false, }) break } } } function firstShortBuy(ticker) { if (SHORT_BUYING) { return } exchange.SetDirection("sell") let orderId = exchange.Sell(ticker.Last, getShortQuantity()) if (!orderId) { return } SHORT_BUYING = true while (true) { let order = exchange.GetOrder(orderId) if (null === order) { continue } if (1 === order.Status || 2 === order.Status) { SHORT_NEXT_BUY_PRICE = order.Price * ((100 + DOUBLE_THROW_RATIO) / 100) SHORT_STEP = SHORT_STEP + 1 SHORT_BUYING = false SHORT_EMPTY_STEP_TIME = null let sellPrice = order.Price * ((100 - PROFIT_RATIO) / 100) SHORT_ORDER_LIST.push({ buyPrice: order.Price, sellPrice: sellPrice, quantity: order.Amount, isSell: false, }) break } } } function manyBuy(ticker) { if (MANY_BUYING) { return } Log('ticker: ' + ticker.Last + ' MANY_NEXT_BUY_PRICE: ' + MANY_NEXT_BUY_PRICE) if (ticker.Last > MANY_NEXT_BUY_PRICE) { return } exchange.SetDirection("buy") let orderId = exchange.Buy(ticker.Last, getManyQuantity()) if (!orderId) { return } MANY_BUYING = true MANY_BUY_TIME = Unix() while (true) { let now = Unix() let order = exchange.GetOrder(orderId) let expire = MANY_BUY_TIME + (60 * 30) if (null === order) { continue } // 买入成功处理 if (1 === order.Status || 2 === order.Status) { MANY_NEXT_BUY_PRICE = order.Price * ((100 - DOUBLE_THROW_RATIO) / 100) MANY_STEP = MANY_STEP + 1 MANY_BUYING = false MANY_EMPTY_STEP_TIME = null let sellPrice = order.Price * ((100 + PROFIT_RATIO) / 100) MANY_ORDER_LIST.push({ buyPrice: order.Price, sellPrice: sellPrice, quantity: order.Amount, isSell: false, }) break } // 买入超时处理 if (now >= expire) { exchange.CancelOrder(orderId) MANY_BUYING = false MANY_BUY_TIME = null MANY_NEXT_BUY_PRICE = ticker.Last * ((100 - DOUBLE_THROW_RATIO) / 100) return } } } function shortBuy(ticker) { if (SHORT_BUYING) { return } Log('ticker: ' + ticker.Last + ' SHORT_NEXT_BUY_PRICE: ' + SHORT_NEXT_BUY_PRICE) if (ticker.Last < SHORT_NEXT_BUY_PRICE) { return } exchange.SetDirection("sell") let orderId = exchange.Sell(ticker.Last, getShortQuantity()) if (!orderId) { return } SHORT_BUYING = true SHORT_BUY_TIME = Unix() while (true) { let now = Unix() let expire = SHORT_BUY_TIME + (60 * 30) let order = exchange.GetOrder(orderId) if (null === order) { continue } // 买入成功处理 if (1 === order.Status || 2 === order.Status) { SHORT_NEXT_BUY_PRICE = order.Price * ((100 + DOUBLE_THROW_RATIO) / 100) SHORT_STEP = SHORT_STEP + 1 SHORT_BUYING = false SHORT_EMPTY_STEP_TIME = null let sellPrice = order.Price * ((100 - PROFIT_RATIO) / 100) SHORT_ORDER_LIST.push({ buyPrice: order.Price, sellPrice: sellPrice, quantity: order.Amount, isSell: false, }) break } // 买入超时处理 if (now >= expire) { exchange.CancelOrder(orderId) SHORT_BUYING = false SHORT_BUY_TIME = null SHORT_NEXT_BUY_PRICE = ticker.Last * ((100 + DOUBLE_THROW_RATIO) / 100) return } } } function manySell(ticker) { // 遍历卖出订单 for (let item of MANY_ORDER_LIST) { if (item.isSell) { continue } if (ticker.Last >= item.sellPrice) { item.isSell = true; exchange.SetDirection("closebuy") let orderId = exchange.Sell(ticker.Last, item.quantity) if (!orderId) { return } while (true) { let order = exchange.GetOrder(orderId) if (null === order) { continue } if (1 === order.Status || 2 === order.Status) { MANY_NEXT_BUY_PRICE = ticker.Last * ((100 - BUY_PRICE_RATIO) / 100) MANY_STEP = MANY_STEP - 1 if (0 === MANY_STEP) { MANY_EMPTY_STEP_TIME = Unix() } break } } } } } function shortSell(ticker) { // 遍历卖出订单 for (let item of SHORT_ORDER_LIST) { if (item.isSell) { continue } if (ticker.Last <= item.sellPrice) { item.isSell = true; exchange.SetDirection("closesell") let orderId = exchange.Buy(ticker.Last, item.quantity) if (!orderId) { return } while (true) { let order = exchange.GetOrder(orderId) if (null === order) { continue } if (1 === order.Status || 2 === order.Status) { SHORT_NEXT_BUY_PRICE = ticker.Last * ((100 + BUY_PRICE_RATIO) / 100) SHORT_STEP = SHORT_STEP - 1 if (0 === SHORT_STEP) { SHORT_EMPTY_STEP_TIME = Unix() } break } } } } } function check(ticker) { let now = Unix() if (null !== CHECK_TIME) { let expire = CHECK_TIME + (60 * 10) if (now < expire) { return } } CHECK_TIME = now if (null !== MANY_EMPTY_STEP_TIME) { let expire = MANY_EMPTY_STEP_TIME + (60 * 30) if (now >= expire) { MANY_NEXT_BUY_PRICE = ticker.Last * ((100 - DOUBLE_THROW_RATIO) / 100) Log('没有买涨持仓, 调整买入价: ' + MANY_NEXT_BUY_PRICE) } } if (null !== SHORT_EMPTY_STEP_TIME) { let expire = SHORT_EMPTY_STEP_TIME + (60 * 30) if (now >= expire) { SHORT_NEXT_BUY_PRICE = ticker.Last * ((100 + DOUBLE_THROW_RATIO) / 100) Log('没有做空持仓, 调整买入价: ' + SHORT_NEXT_BUY_PRICE) } } } function onTick() { // 在这里写策略逻辑,将会不断调用,例如打印行情信息 let ticker = exchange.GetTicker() if (!ticker) { return } if (FIRST_BUY) { // 首次做多购买 firstManyBuy(ticker) // 首次做空购买 firstShortBuy(ticker) FIRST_BUY = false return } // 做多买入 manyBuy(ticker) // 做空买入 shortBuy(ticker) // 做多卖出 manySell(ticker) // 做空卖出 shortSell(ticker) // 空仓检测 check(ticker) } function main() { // 开合约 exchange.SetContractType("swap") while(true){ onTick() // Sleep函数主要用于数字货币策略的轮询频率控制,防止访问交易所API接口过于频繁 Sleep(60000) } }
hexie8 可以多币种吗
rich_rory check是什么意思。。。。定期增加/减少 买入门槛? 有什么意义
artron 这个怎么没有策略参数设置?
Exodus[策略代写] 又发现问题了呢,在回测2020-1-1到2020-6月的时候,到3-30号整个机器人就停止了,此外,测试ETH的时候在测试2021-1-1到201-6-21的时候在1-2号就会停止呢,不知道是fmz的问题还是机器人的问题呢。作者可以自己测试一下
evan 不能算是真正的 多空对冲啊 像合约网格啊
Exodus[策略代写] 加作者微信没有回应,只能来这里说几句了,运行了7天,200刀本金赚了70刀。挺不错的,但是在运行期间我发现了几个问题。 1.双向开单功能是正常的嘛?看策略里说双向看单,爆仓几率很小,可是七天内除了机器人刚启动时开了双向单,几乎没有双向开单,经过我的研究发现是10分钟更新一次开单位置,这导致变化较慢时毫无意义,也开不了双向单,比如今天btc今天5%的跌幅竟然没有开单?这里是否需要优化呢?比如延长检测间隔?此外,在大行情中就算假突破开了双向单,假突破一方也是最低档,不太理解有什么意义。还是说双向是指能吃两边行情,而对阻止爆仓没有什么意义吗? 2.爆就默认的加仓资金来说,想不暴仓需要确保1000刀到2000刀以上的资金,我两百刀今天要是没有莫名其妙醒过来我已经爆仓了,临时加的保证金。如果资金不够也可以自己手动调整加仓的数量,这里提醒一下,免得不会看代码的爆仓了。 3.请问一下,因为永不止损嘛,所以在本金足够的情况下是否永远不会爆仓呢,可是回测中为何会出现亏损呢?按理来说亏损就是爆仓,就是资金归零才对呀,我哪里理解错了吗,求指点。 这个策略我挺喜欢的,可以无视方向就能获利,调整加仓量和本金的话爆仓风险也不大,感觉调整开空和开多的价格可以优化,根据本金加入自适应加仓量等等
YesX 老哥微信
Exodus[策略代写] 解决了,换成币安就行了
Exodus[策略代写] 看回测感觉好叼,但是好像不能用在实盘吗?我火币开bch的会报错,Sell(490.14, 0.001): map[err_code:1067 err_msg:The volume field is illegal. Please re-enter. status:error ts:1.625132342294e+12]。合约后面不是张数吗,为什么是小数呢
wbsy 没有实盘么
Exodus[策略代写] 这收益曲线太可怕了吧,亏了120%多
醉里挑灯看剑 笑死我了
Exodus[策略代写] 难受,今天亏爆了,很期待2.0,请问怎样才能体验新策略呢
wind 在开发2.0版本中发现了这些问题 做空买不进的原因是,开单的百分比是固定的,也就是涨百分之一,做空 ,跌百分之一,买涨 由于涨跌都是百分之一,涨跌买入百分比一致,从1000涨到1500,1000的百分之一和1500的百分之一是不一样的,所以做空比较难买进,而且改价太过于频繁更导致做空可能买不进 止损问题,在2.0版本中做了一定的处理,很简单的一个止损处理,但是从回测数据来看效果还可以,当你买涨或者做空仓位达到一定阀值时开始全仓卖出,1.0没有处理所以会出现部分订单永远都无法成交,比如在btc 65000买涨数量0.001,那么btc跌了这个单子永远出不去了 /upload/asset/2034c4ec56c423120b9c6.png /upload/asset/203032c94e60a3915cc9f.png /upload/asset/2030b880b030476977f4b.png /upload/asset/2030d89e9fd59f528be4c.png
wind 我用币安回测 跑的实盘 其他平台可能会报一些错误
wind 实盘还在跑,需要时间
wind 看看最新的曲线,之前的刚写出来有bug