সবচেয়ে ক্লাসিক একক মুদ্রার ভারসাম্য কৌশল, বিক্রি করা, কেনা, সবসময় একটি নির্দিষ্ট অনুপাত বজায় রাখা; তুলনায় মাঝারি মুদ্রা কৌশল, দীর্ঘমেয়াদী অপারেশন প্রয়োজন।
/*backtest start: 2019-07-24 00:00:00 end: 2020-07-23 23:59:00 period: 1h basePeriod: 1h exchanges: [{"eid":"Binance","currency":"BTC_USDT","stocks":1.2,"fee":[0.1,0.1]}] */ var order = {buy_price:0,buy_amount:0,buy_id:0,sell_price:0,sell_amount:0,sell_id:0} var account = null var last = 0 var symbol = '' var log_profit_time = 0 var update_status_time = 0 var update_alpha_time = Date.now() var total_trade_volume = 0 if(exchange.GetName().slice(0,7) == 'Futures'){ throw '此策略只支持现货' } if(Ratio < 0.0005){ throw '网格密度勿小于万分之5' } if(_G('symbol')){ symbol = _G('symbol') }else{ symbol = exchange.GetCurrency() _G('symbol', symbol) } if(exchange.GetCurrency() != symbol){ throw '不可更换币种,需要重新建立新机器人' } function GetPrecision(){ if(IsVirtual()){ return {price:6, amount:6} } var precision = {price:0, amount:0} var depth = exchange.GetDepth() if(!depth){ throw '无法连接交易所行情,需要海外托管者' } for(var i=0;i<depth.Asks.length;i++){ var amountPrecision = depth.Asks[i].Amount.toString().indexOf('.') > -1 ? depth.Asks[i].Amount.toString().split('.')[1].length : 0 precision.amount = Math.max(precision.amount,amountPrecision) var pricePrecision = depth.Asks[i].Price.toString().indexOf('.') > -1 ? depth.Asks[i].Price.toString().split('.')[1].length : 0 precision.price = Math.max(precision.price,pricePrecision) } return precision } function updateAccount() { var acc = exchange.GetAccount() if(acc){ if(account && _N(acc.Stocks + acc.FrozenStocks,6) != _N(account.Stocks + account.FrozenStocks,6)){ if(acc.Stocks + acc.FrozenStocks > account.Stocks + account.FrozenStocks){ Log('买单成交:',_N(acc.Stocks + acc.FrozenStocks-account.Stocks - account.FrozenStocks,6), ' 数量变动:', _N(account.Stocks + account.FrozenStocks,6), ' -> ', _N(acc.Stocks + acc.FrozenStocks,6)) } if(acc.Stocks + acc.FrozenStocks < account.Stocks + account.FrozenStocks){ Log('卖单成交:',_N(account.Stocks + account.FrozenStocks - acc.Stocks - acc.FrozenStocks,6),' 数量变动:', _N(account.Stocks + account.FrozenStocks,6), ' -> ', _N(acc.Stocks + acc.FrozenStocks,6)) } total_trade_volume += _N(Math.abs(acc.Stocks + acc.FrozenStocks - (account.Stocks + account.FrozenStocks)),6) } account = acc }else{ Log('获取账户信息出错') } } function updateTicker(){ var ticker = exchange.GetTicker() if(ticker){ last = ticker.Last }else{ Log('获取行情出错') } } function cancelAll(){ Log('撤销所有订单') var orders = exchange.GetOrders() if(!orders){ Log('获取订单失败') } for(var j=0; j<orders.length; j++){ exchange.CancelOrder(orders[j].Id) Sleep(10) } } cancelAll() last = exchange.GetTicker().Last updateAccount() var precision = GetPrecision() var init_value = 0 var init_account = {balance:0, amount:0} if(_G('init_value')){ init_value = _G('init_value') init_account = _G('init_account') }else{ init_value = _N(account.Balance+account.FrozenBalance+(account.Stocks+account.FrozenStocks)*last, 6) init_account = {balance:account.Balance+account.FrozenBalance, amount:account.Stocks+account.FrozenStocks} Log('第一次启动策略, 始总价值为: ', init_value) _G('init_value', init_value) _G('init_account', init_account) } function trade(direction, price, value, msg){ if(price <= 0){return} var amount = _N(value/price, precision.amount) var new_order = false if(!order[direction+'_id']){ new_order = true } if(order[direction+'_price'] > 0 && Math.abs(price-order[direction+'_price'])/order[direction+'_price'] > Grid_Ratio/10.0){ new_order = true } if((direction == 'buy' && account.FrozenBalance == 0 && account.Balance > 1.5*value) || (direction == 'sell' && account.FrozenStocks == 0 && account.Stocks > 1.5*amount)){ new_order = true } order[direction+'_price'] = price if(new_order){ if(order[direction+'_id']){ exchange.CancelOrder(order[direction+'_id']) order[direction+'_price'] = 0 order[direction+'_id'] = 0 } var id =null if(direction == 'buy'){ if(account.Balance < 1.5*value){ Log('资金不足, 无法挂买单') }else{ id = exchange.Buy(price, amount, msg) } } if(direction == 'sell'){ if(account.Stocks < 1.5*amount){ Log('余币不足, 无法挂卖单') }else{ id = exchange.Sell(price, amount, msg) } } order[direction+'_id'] = id order[direction+'_price'] = price } } function updateStatus(){ if(Date.now()-update_status_time < 4000){ return } update_status_time = Date.now() var now_value = (account.Stocks+account.FrozenStocks)*last + account.Balance+account.FrozenBalance var profit = _N( now_value - init_account.amount*last - init_account.balance, 6) var table = { type: 'table', title: '账户信息', cols: ['初始币', '初始资金', '当前币', '当前资金', '当前比例', '现价', '初始市值', '当前市值', '总成交', '收益'], rows: [[_N(init_account.amount,6), _N(init_account.balance,6), _N(account.Stocks+account.FrozenStocks,6), _N(account.Balance+account.FrozenBalance,6), _N((account.Stocks+account.FrozenStocks)*last/now_value,6), _N(last,6), _N(init_value,6), _N(now_value,6),_N(total_trade_volume,4), _N(profit,6)]] } var logString = _D()+' 策略代码最后更新时间6月10日 14:00\n' LogStatus(logString + '`' + JSON.stringify(table) + '`'+'\n') var log_profit_intervel = IsVirtual() ? 24*60*60*1000 : Log_profit if(Date.now()-log_profit_time > log_profit_intervel){ LogProfit(_N((account.Stocks+account.FrozenStocks)*last + account.Balance+account.FrozenBalance - init_account.amount*last - init_account.balance, 6)) log_profit_time = Date.now() } } function onTick(){ if(last == 0){return} var m = account.Stocks+account.FrozenStocks var b = account.Balance+account.FrozenBalance var r = m*last/(m*last+b) if(Math.abs(r-Ratio)>0.3*Ratio){ throw '为避免冲击市场,需要手动交易到持仓比例附近,再由策略进行交易' } var buy_r = Ratio-Grid_Ratio var sell_r = Ratio+Grid_Ratio var buy_price = _N(b*buy_r/(m-m*buy_r), precision.price) var sell_price = _N(b*sell_r/(m-m*sell_r), precision.price) var buy_value = (m*buy_price + b)*Grid_Ratio var sell_value = (m*sell_price + b)*Grid_Ratio trade('buy', buy_price, buy_value, '买入平衡') trade('sell', sell_price, sell_value , '卖出平衡') } function onexit(){ cancelAll() } function main() { while(true){ updateTicker() updateAccount() onTick() updateStatus() if(!IsVirtual()){ Sleep(Intervel) } } }
পরিমাণগত লেনদেনএই সম্পদ ভারসাম্য কৌশলটি কি লাভজনক?
ঘাসদীর্ঘ সময় ধরে দৌড়ানো উচিত, আবার চেষ্টা করা উচিত।