Loading ...

币安永续多币种对冲策略(做多超跌做空超涨) (张总python版)

Author: 汇链资本, Date: 2020-04-24 18:10:05
Tags:


#刚学python,希望指正!共同学习!
import time
import requests
import math
Alpha = 0.001 #指数移动平均的Alpha参数,设置的越大,基准价格跟踪越敏感,最终持仓也会越低,降低了杠杆,但会降低收益,具体需要根据回测结果自己权衡
Update_base_price_time_interval = 60 #多久更新一次基准价格, 单位秒,和Alpha参数相关,Alpha 设置的越小,这个间隔也可以设置的更小
#Stop_loss设置为0.8表示当资金达到低于初始资金的80%时,止损,清空所有仓位,停止策略。
#随着策略运行,Stop_loss可以设置大于1(重启生效),比如从1000赚到1500,Stop_loss设置为1.3,则回撤到1300元止损。不想止损可以把这个参数设置的很小。
#风险是大家都用这种止损会形成踩踏,加大亏损。
#初始资金在状态栏的init_balance字段,注意提现等操作会影响,别不小心止损了。
#如果还是怕黑天鹅事件,比如某个币归0等,可以手动提现出来。

Stop_loss = 0.8
Max_diff = 0.03 #当偏差diff大于0.4时,不继续加空仓, 自行设置
Min_diff = -0.03 #当diff小于-0.3时,不继续加多仓, 自行设置
Version = '0.1.3'
Show = false #默认为false累计收益显示是账户余额,改为true累计收益显示为收益,如果之前是显示的账户余额,你使用LogProfitReset()来清空图表
Funding = 0 #账户初始金额,为0的时候,自动获取,非0为自定义
success = '#5cb85c' #成功颜色
danger = '#ff0000' #危险颜色
warning = '#f0ad4e' #警告颜色
RunTime = {} #运行时间
SelfFee = 0.04 #https:#www.binance.com/cn/fee/futureFee
TotalLong = 0
TotalShort = 0
UpProfit = 0
accountAssets = [] #保存资产
WinRateData = {} #保存所有币种的胜率及开仓次数

if IsVirtual():
    Log('不能回测,回测参考 https://www.fmz.com/digest-topic/5294 ')
    exit()
if exchange.GetName() != 'Futures_Binance':
    Log('只支持币安期货交易所,和现货交易所不同,需要单独添加,名称为Futures_Binance')
    exit()
trade_symbols = Trade_symbols.split(',')
symbols = trade_symbols + ['BTC']
index = 1 #指数
update_profit_time = 0
update_base_price_time = int(time.time()*1000)
assets = {}
init_prices = {}
trade_info = {}

def init():
    InitRateData()
    exchange_info = requests.get('https://fapi.binance.com/fapi/v1/exchangeInfo').json()
    if exchange_info is None:
        Log('无法连接币安网络,需要海外托管者')
        exit()    
    for i in range(len(exchange_info['symbols'])):
        if exchange_info['symbols'][i]['baseAsset'] in symbols:            
            assets[exchange_info['symbols'][i]['baseAsset']] = {'amount': 0,'hold_price': 0,'value': 0,'bid_price': 0,'ask_price': 0,'btc_price': 0, 'btc_change': 1,'btc_diff': 0,'realised_profit': 0,'margin': 0,'unrealised_profit': 0,'leverage': 20, 'positionInitialMargin': 0,  'liquidationPrice': 0 }
            trade_info[exchange_info['symbols'][i]['baseAsset']] = {'minQty': float(exchange_info['symbols'][i]['filters'][1]['minQty']) , 'priceSize': int((math.log10(1.1/float(exchange_info['symbols'][i]['filters'][0]['tickSize'])))),'amountSize': int((math.log10(1.1/float(exchange_info['symbols'][i]['filters'][1]['stepSize']))))}

assets['USDT'] = {
    'unrealised_profit': 0,
    'margin': 0,
    'margin_balance': 0,
    'total_balance': 0,
    'leverage': 0,
    'update_time': 0,
    'margin_ratio': 0,
    'init_balance': 0,
    'stop_balance': 0,
    'short_value': 0,
    'long_value': 0,
    'profit': 0
}

def updateAccount() : #更新账户和持仓
    global accountAssets
    account = exchange.GetAccount()
    pos = exchange.GetPosition()
    if account is None or pos is None:
        Log('update account time out')
        return    
    accountAssets = account['Info']['assets']
    assets['USDT']['update_time'] = int(time.time()*1000)
    for i in range(len(trade_symbols)):
        assets[trade_symbols[i]]['margin'] = 0
        assets[trade_symbols[i]]['unrealised_profit'] = 0
        assets[trade_symbols[i]]['hold_price'] = 0
        assets[trade_symbols[i]]['amount'] = 0
    
    for j in range(len(account['Info']['positions'])):        
        if account['Info']['positions'][j]['positionSide'] == 'BOTH':
            pair = account['Info']['positions'][j]['symbol']
            coin = pair[0:len(pair)-4]
            if coin not in trade_symbols:
                continue
            assets[coin]['margin'] = float(account['Info']['positions'][j]['initialMargin']) + float(account['Info']['positions'][j]['maintMargin'])
            assets[coin]['unrealised_profit'] = float(account['Info']['positions'][j]['unrealizedProfit'])
            assets[coin]['positionInitialMargin'] = float(account['Info']['positions'][j]['positionInitialMargin'])
            assets[coin]['leverage'] = account['Info']['positions'][j]['leverage']

    assets['USDT']['margin'] = _N(float(account['Info']['totalInitialMargin']) + float(account['Info']['totalMaintMargin']), 2)
    assets['USDT']['margin_balance'] = _N(float(account['Info']['totalMarginBalance']), 2)
    assets['USDT']['total_balance'] = _N(float(account['Info']['totalWalletBalance']), 2)
    if assets['USDT']['init_balance'] == 0:
        if _G('init_balance'):
            assets['USDT']['init_balance'] = _N(_G('init_balance'), 2)
        else:
            assets['USDT']['init_balance'] = assets['USDT']['total_balance']
            _G('init_balance', assets['USDT']['init_balance'])
    assets['USDT']['profit'] = _N(assets['USDT']['margin_balance'] - assets['USDT']['init_balance'], 2)
    assets['USDT']['stop_balance'] = _N(Stop_loss * assets['USDT']['init_balance'], 2)
    assets['USDT']['total_balance'] = _N(float(account['Info']['totalWalletBalance']), 2)
    assets['USDT']['unrealised_profit'] = _N(float(account['Info']['totalUnrealizedProfit']), 2)
    assets['USDT']['leverage'] = _N(assets['USDT']['margin'] / assets['USDT']['total_balance'], 2)
    assets['USDT']['margin_ratio'] = float(account['Info']['totalMaintMargin']) / float(account['Info']['totalMarginBalance']) * 100
    pos = json.loads(exchange.GetRawJSON())
    if len(pos) > 0:
        for k in range(len(pos)):
            pair = pos[k]['symbol']
            coin = pair[0:len(pair)-4]
            if coin not in trade_symbols:
                continue            
            if pos[k]['positionSide'] != 'BOTH':
                continue       
            assets[coin]['hold_price'] = float(pos[k]['entryPrice'])
            assets[coin]['amount'] = float(pos[k]['positionAmt'])
            assets[coin]['unrealised_profit'] = float(pos[k]['unRealizedProfit'])
            assets[coin]['liquidationPrice'] = float(pos[k]['liquidationPrice'])
            assets[coin]['marginType'] = pos[k]['marginType']

def updateIndex(): #更新指数
    global update_base_price_time,index,init_prices,Reset
    if _G('init_prices') is None or Reset:
        Reset = False
        for i in range(len(trade_symbols)):
            init_prices[trade_symbols[i]] = (assets[trade_symbols[i]]['ask_price'] + assets[trade_symbols[i]]['bid_price']) / (assets['BTC']['ask_price'] + assets['BTC']['bid_price'])
        Log('保存启动时的价格')
        _G('init_prices', init_prices)
        _G("StartTime", None) #重置开始时间
        _G("initialAccount_" + exchange.GetLabel(), None) #重置开始资金
        _G('tradeNumber', 0) #重置交易次数
        _G('tradeVolume', 0) #重置交易量
        _G('buyNumber', 0) #重置做多次数
        _G('sellNumber', 0) #重置做空次数
        _G('totalProfit', 0) #重置打印次数
        _G('profitNumber', 0) #重置盈利次数
    else:
        init_prices = _G('init_prices')
        if (int(time.time()*1000) - update_base_price_time > Update_base_price_time_interval * 1000):
            update_base_price_time = int(time.time()*1000)
            for i in range(len(trade_symbols)): #更新初始价格
                init_prices[trade_symbols[i]] = init_prices[trade_symbols[i]] * (1 - Alpha) + Alpha * (assets[trade_symbols[i]]['ask_price'] + assets[trade_symbols[i]]['bid_price']) / (assets['BTC']['ask_price'] + assets['BTC']['bid_price'])
            _G('init_prices', init_prices)
        temp = 0
        for i in range(len(trade_symbols)):
            assets[trade_symbols[i]]['btc_price'] = (assets[trade_symbols[i]]['ask_price'] + assets[trade_symbols[i]]['bid_price']) / (assets['BTC']['ask_price'] + assets['BTC']['bid_price'])
            if trade_symbols[i] not in init_prices:
                Log('添加新的币种', trade_symbols[i])
                init_prices[trade_symbols[i]] = assets[trade_symbols[i]]['btc_price']
                _G('init_prices', init_prices)
            assets[trade_symbols[i]]['btc_change'] = _N(assets[trade_symbols[i]]['btc_price'] / init_prices[trade_symbols[i]], 4)
            temp += assets[trade_symbols[i]]['btc_change']        
        index = _N(temp / len(trade_symbols), 4)

def updateTick() : #更新行情
    try:
        ticker = requests.get('https://fapi.binance.com/fapi/v1/ticker/bookTicker').json()
    except Exception as e:
        Log('get ticker time out:',e)
        return
    assets['USDT']['short_value'] = 0
    assets['USDT']['long_value'] = 0
    for i in range(len(ticker)):
        pair = ticker[i]['symbol']
        coin = pair[0:len(pair)-4]
        if coin not in symbols:
            continue
        assets[coin]['ask_price'] = float(ticker[i]['askPrice'])
        assets[coin]['bid_price'] = float(ticker[i]['bidPrice'])
        assets[coin]['ask_value'] = _N(assets[coin]['amount'] * assets[coin]['ask_price'], 2)
        assets[coin]['bid_value'] = _N(assets[coin]['amount'] * assets[coin]['bid_price'], 2)
        if coin not in trade_symbols:
            continue
        if assets[coin]['amount'] < 0 :
            assets['USDT']['short_value'] += abs((assets[coin]['ask_value'] + assets[coin]['bid_value']) / 2)
        else:
            assets['USDT']['long_value'] += abs((assets[coin]['ask_value'] + assets[coin]['bid_value']) / 2)        
        assets['USDT']['short_value'] = _N(assets['USDT']['short_value'], 0)
        assets['USDT']['long_value'] = _N(assets['USDT']['long_value'], 0)    
    updateIndex()
    for i in range(len(trade_symbols)):
        assets[trade_symbols[i]]['btc_diff'] = _N(assets[trade_symbols[i]]['btc_change'] - index, 4)

def trade(symbol, dirction, value) : #交易
    if (int(time.time()*1000) - assets['USDT']['update_time'] > 10 * 1000):
        Log('更新账户延时,不交易')
    else:
        price = assets[symbol]['bid_price'] if dirction == 'sell' else assets[symbol]['ask_price']
        amount = _N(min(value, Ice_value) / price, trade_info[symbol]['amountSize'])
        if amount < trade_info[symbol]['minQty']:
            Log(symbol, '合约价值偏离或冰山委托订单的大小设置过小,达不到最小成交, 至少需要: ', _N(trade_info[symbol]['minQty'] * price, 0) + 1)
        else:
            exchange.IO("currency", symbol + '_' + 'USDT')
            exchange.SetContractType('swap')
            exchange.SetDirection(dirction)
            #f = 'Buy' if dirction == 'buy' else 'Sell'
            place_order = getattr(exchange,'Buy' if dirction == 'buy' else 'Sell')
            id = place_order(price, amount, symbol)
            if id:
                exchange.CancelOrder(id) #订单会立即撤销
            tradingCounter('tradeVolume', price * amount) #保存交易量
            tradingCounter('tradeNumber', 1) #保存交易次数
            WinRateData[symbol]['tradeNumber'] += 1
            if dirction == 'buy':
                tradingCounter('buyNumber', 1)
                WinRateData[symbol].buyNumber += 1
            else:
                tradingCounter('sellNumber', 1)
                WinRateData[symbol].sellNumber += 1            
            _G("WinRateData", WinRateData) #保存各币种的交易数据
            return id

def InitRateData():
    global WinRateData
    if Reset :
        _G("WinRateData", None)    
    if _G("WinRateData"):
        WinRateData = _G("WinRateData")    
    for i in range(len(symbols)):        
        if symbols[i] not in WinRateData:
            WinRateData[symbols[i]] = {'totalProfit': 0, 'profitNumber': 0,'tradeNumber': 0,'buyNumber': 0, 'sellNumber': 0}
                                            #统计次数        #盈利次数          #交易次数       #做多次数        #做空次数
    _G("WinRateData", WinRateData)

def RunCommand():
    str_cmd = GetCommand()
    if str_cmd:
        arrCmd = str_cmd.split(':')
        symbol = arrCmd[1]
        amount = float(arrCmd[2])
        if amount == 0:
            Log('亲,你还记得大明湖畔的乔碧萝吗?' + danger)
        else:
            #f = 'Buy' if amount < 0 else 'Sell'
            dirction = 'buy' if amount < 0 else 'sell'
            exchange.IO("currency", symbol + '_' + 'USDT')
            exchange.SetContractType('swap')
            exchange.SetDirection(dirction)
            place_order = getattr(exchange,'Buy' if dirction == 'buy' else 'Sell')
            id = place_order(-1, abs(amount), symbol)
            #exchange[f](-1, abs(amount), symbol)

def FirstAccount():
    key = "initialAccount_" + exchange.GetLabel()
    initialAccount = _G(key)
    if initialAccount is None:
        initialAccount = exchange.GetAccount()
        _G(key, initialAccount)    
    return initialAccount

def StartTime():
    StartTime = _G("StartTime")
    if StartTime is None:
        StartTime = _D()
        _G("StartTime", StartTime)    
    return StartTime

def RuningTime():
    ret = {}    
    dateBegin = StartTime()
    dateEnd = _D()
    dateDiff = (time.mktime(time.strptime(dateEnd, '%Y-%m-%d %H:%M:%S')) - time.mktime(time.strptime(dateBegin, '%Y-%m-%d %H:%M:%S'))) * 1000
    dayDiff = math.floor(dateDiff / (24 * 3600 * 1000))
    leave1 = dateDiff % (24 * 3600 * 1000)
    hours = math.floor(leave1 / (3600 * 1000))
    leave2 = leave1 % (3600 * 1000)
    minutes = math.floor(leave2 / (60 * 1000))
    ret['dayDiff'] = dayDiff
    ret['hours'] = hours
    ret['minutes'] = minutes
    ret['str'] = "运行时间: " + str(dayDiff) + " 天 " + str(hours) + " 小时 " + str(minutes) + " 分钟"
    return ret

def AppendedStatus():
    global TotalLong , TotalShort,RunTime,Funding, accountAssets
    accountTable = {
        'type': "table",
        'title': "盈利统计",
        'cols': ["运行天数", "初始资金", "现有资金", "保证金余额", "已用保证金", "保证金比率", "止损", "总收益", "预计年化", "预计月化", "平均日化"],
        'rows': []
    }
    feeTable = {
        'type': 'table',
        'title': '交易统计',
        'cols': ["策略指数", '交易次数', '做多次数', '做空次数', '预估胜率', '预估成交额', '预估手续费', "未实现盈利", '持仓总值', '做多总值', '做空总值'],
        'rows': []
    }
    runday = RunTime['dayDiff']
    if runday == 0:
        runday = 1
    if Funding == 0:
        Funding = float(FirstAccount()['Info']['totalWalletBalance'])
    profitColors = danger
    totalProfit = assets['USDT']['total_balance'] - Funding #总盈利
    if totalProfit > 0:
        profitColors = success
    dayProfit = totalProfit / runday #天盈利
    dayRate = dayProfit / Funding * 100
    accountTable['rows'].append([
        runday,
        '$' + str(_N(Funding, 2)),
        '$' + str(assets['USDT']['total_balance']),
        '$' + str(assets['USDT']['margin_balance']),
        '$' + str(assets['USDT']['margin']),
        str(_N(assets['USDT']['margin_ratio'], 2)) + '%',
        str(_N(assets['USDT']['stop_balance'], 2)) + danger,
        str(_N(totalProfit / Funding * 100, 2)) + "% = $" + str(_N(totalProfit, 2)) + (profitColors),
        str(_N(dayRate * 365, 2)) + "% = $" + str(_N(dayProfit * 365, 2)) + (profitColors),
        str(_N(dayRate * 30, 2)) + "% = $" + str(_N(dayProfit * 30, 2)) + (profitColors),
        str(_N(dayRate, 2)) + "% = $" + str(_N(dayProfit, 2)) + (profitColors)
    ])
    vloume = _G('tradeVolume') if _G('tradeVolume') is not None else 0
    feeTable['rows'].append([
        index, #指数
        _G('tradeNumber') if _G('tradeNumber') is not None else 0, #交易次数
        _G('buyNumber') if _G('buyNumber') is not None else 0, #做多次数
        _G('sellNumber') if _G('sellNumber') is not None else 0, #做空次数
        str(_N(_G('profitNumber') / _G('totalProfit') * 100, 2) if _G('totalProfit') > 0 else 0) + '%', #胜率
        '$' + str(_N(vloume, 2)) + ' ≈ ฿' + str(_N(vloume / ((assets['BTC']['bid_price'] + assets['BTC']['ask_price']) / 2), 6)), #成交金额
        '$' + str(_N(vloume * (SelfFee / 100), 4)), #手续费
        '$' + str(_N(assets['USDT']['unrealised_profit'], 2)) + (success if assets['USDT']['unrealised_profit'] >= 0 else danger),
        '$' + str(_N(TotalLong + abs(TotalShort), 2)), #持仓总价值
        '$' + str(_N(TotalLong, 2)) + success, #做多总值
        '$' + str(_N(abs(TotalShort), 2)) + danger, #做空总值
    ])
    assetTable = {
        'type': 'table',
        'title': '账户资产信息',
        'cols': ['编号', '资产名', '起始保证金', '维持保证金', '保证金余额', '最大可提款金额', '挂单起始保证金', '持仓起始保证金', '持仓未实现盈亏', '账户余额'],
        'rows': []
    }
    for i in range(len(accountAssets)):
        acc = accountAssets[i]
        assetTable['rows'].append([
            i + 1,
            acc['asset'], acc['initialMargin'], acc['maintMargin'], acc['marginBalance'],
            acc['maxWithdrawAmount'], acc['openOrderInitialMargin'], acc['positionInitialMargin'],
            acc['unrealizedProfit'], acc['walletBalance']
        ])
    indexTable = {
        'type': 'table',
        'title': '币指数信息',
        'cols': ['编号', '币种信息', '当前价格', 'BTC计价', 'BTC计价变化(%)', '偏离平均', '交易次数', '做空次数', '做多次数', '预估胜率'],
        'rows': []
    }
    for i in range(len(symbols)) :
        price = _N((assets[symbols[i]]['ask_price'] + assets[symbols[i]]['bid_price']) / 2, trade_info[symbols[i]]['priceSize'])
        if symbols[i] not in symbols:
            indexTable['rows'].append([i + 1, symbols[i], price, assets[symbols[i]]['btc_price'], _N((1 - assets[symbols[i]]['btc_change']) * 100), assets[symbols[i]]['btc_diff']], 0, 0, 0, '0%')
        else:
            rateData = _G("WinRateData")
            winRate = _N(rateData[symbols[i]]['profitNumber'] / rateData[symbols[i]]['totalProfit'] * 100, 2) if rateData[symbols[i]]['totalProfit'] > 0 else 0
            indexTable['rows'].append([
                (i + 1),
                symbols[i] + warning,
                price,
                _N(assets[symbols[i]]['btc_price'], 6),
                _N((1 - assets[symbols[i]]['btc_change']) * 100),
                str(assets[symbols[i]]['btc_diff']) + (success if assets[symbols[i]]['btc_diff'] >= 0 else danger),
                rateData[symbols[i]]['tradeNumber'],
                rateData[symbols[i]]['sellNumber'],
                rateData[symbols[i]]['buyNumber'],
                (str(winRate) if rateData[symbols[i]]['profitNumber'] > 0 and rateData[symbols[i]]['totalProfit'] > 0 else '0') + '%' + (success if winRate >= 50 else danger), #胜率
            ])    
    retData = {}
    retData['upTable'] = RunTime['str'] + '\n' + "最后更新: " + _D() + '\n' + 'Version:' + Version + '\n' + '`' + json.dumps([accountTable, assetTable]) + '`\n' + '`' + json.dumps(feeTable) + '`\n'
    retData['indexTable'] = indexTable
    return retData


def WinRate():
    global WinRateData
    for i in range(len(symbols)) :
        unrealised = assets[symbols[i]]['unrealised_profit']
        WinRateData[symbols[i]]['totalProfit'] += 1
        if unrealised != 0:
            if unrealised > 0:
                WinRateData[symbols[i]]['profitNumber'] += 1    
    _G("WinRateData", WinRateData)

def tradingCounter(key, newValue):
    value = _G(key)
    if value is None:
        _G(key, newValue)
    else:
        _G(key, value + newValue)

def updateStatus() : #状态栏信息
    global TotalLong , TotalShort,Funding,update_profit_time,UpProfit
    TotalLong = 0
    TotalShort = 0
    table = {
        'type': 'table',
        'title': '交易对信息',
        'cols': ['编号', '[模式][倍数]', '币种信息', '开仓方向', '开仓数量', '持仓价格', '当前价格', '强平价格', '强平差价', '持仓价值', '保证金', '未实现盈亏', '投降'],
        'rows': []
    }
    
    for i in range(len(symbols)):        
        direction = '空仓'
        margin = direction
        if assets[symbols[i]]['amount'] != 0:
            direction = '做多' + success if assets[symbols[i]]['amount'] > 0 else '做空' + danger
            margin = '全仓' if assets[symbols[i]]['marginType'] == 'cross' else '逐仓'
        price = _N((assets[symbols[i]]['ask_price'] + assets[symbols[i]]['bid_price']) / 2, trade_info[symbols[i]]['priceSize'])
        value = _N((assets[symbols[i]]['ask_value'] + assets[symbols[i]]['bid_value']) / 2, 2)
        if value != 0:
            if value > 0:
                TotalLong += value
            else:
                TotalShort += value
        # rateData = _G("WinRateData")
        infoList = [
            i + 1,
            "[" + margin + "] [" + str(assets[symbols[i]]['leverage']) + 'x] ',
            symbols[i],
            direction,
            abs(assets[symbols[i]]['amount']),
            assets[symbols[i]]['hold_price'],
            price,
            assets[symbols[i]]['liquidationPrice'], #强平价格
            '0' if assets[symbols[i]]['liquidationPrice'] == 0 else '$' + str(_N(assets[symbols[i]]['liquidationPrice'] - price, 5)) + ' ≈ ' + str(_N(assets[symbols[i]]['liquidationPrice'] / price * 100, 2)) + '%' + warning, #强平价格
            abs(value),
            _N(assets[symbols[i]]['positionInitialMargin'], 2),
            # assets[symbols[i]]['btc_diff'],
            str(_N(assets[symbols[i]]['unrealised_profit'], 3)) + (success if assets[symbols[i]]['unrealised_profit'] >= 0 else danger),
            # (rateData[symbols[i]]['profit']Number > 0 and rateData[symbols[i]].totalProfit > 0 ? _N(rateData[symbols[i]]['profit']Number / rateData[symbols[i]].totalProfit * 100, 2) : '0') + '%', #胜率
            {
                'type': 'button',
                'cmd': '说好的没有撤退可言呢???:' + symbols[i] + ':' + str(assets[symbols[i]]['amount']) + ':',
                'name': symbols[i] + ' 投降'
            }
        ]
        table['rows'].append(infoList)
    #del assets['USDT']['update_time'] #时间戳没什么用,不要了
    logString = json.dumps(assets['USDT']) + '\n'
    StatusData = AppendedStatus()
    LogStatus(StatusData['upTable'] + '`' + json.dumps([table, StatusData['indexTable']]) + '`\n' + logString)

    if int(time.time()*1000) - update_profit_time > Log_profit_interval * 1000:
        balance = assets['USDT']['margin_balance']
        if Show:
            balance = assets['USDT']['margin_balance'] - Funding
        LogProfit(_N(balance, 3), '&')
        update_profit_time = int(time.time()*1000)
        if UpProfit != 0 and (_N(balance, 0) != UpProfit): #第一次不计算,并且小数点面的不进行胜率计算
            tradingCounter("totalProfit", 1) #统计打印次数, 胜率=盈利次数/打印次数*100
            if _N(balance, 0) > UpProfit:
                tradingCounter('profitNumber', 1) #盈利次数
            WinRate()
        UpProfit = _N(balance, 0)

def stopLoss() : #止损函数
    while True:
        if assets['USDT']['margin_balance'] < Stop_loss * assets['USDT']['init_balance'] and assets['USDT']['init_balance'] > 0:
            Log('触发止损,当前资金:', assets['USDT']['margin_balance'], '初始资金:', assets['USDT']['init_balance'])
            Ice_value = 200 #止损的快一些,可修改
            updateAccount()
            updateTick()
            trading = False #是否正在交易
            for i in range(len(trade_symbols)):
                symbol = trade_symbols[i]
                if assets[symbol]['ask_price'] == 0:
                    continue                
                if assets[symbol]['bid_value'] >= trade_info[symbol]['minQty'] * assets[symbol]['bid_price']:
                    trade(symbol, 'sell', assets[symbol]['bid_value'])
                    trading = True
                if assets[symbol]['ask_value'] <= -trade_info[symbol]['minQty'] * assets[symbol]['ask_price']:
                    trade(symbol, 'buy', -assets[symbol]['ask_value'])
                    trading = True
            Sleep(1000)
            if not trading :
                Log('止损结束,如果需要重新运行策略,需要调低止损') 
                exit()
        else : #不用止损
            return None

def onTick() : #策略逻辑部分
    for i in range(len(trade_symbols)) :
        symbol = trade_symbols[i]
        if assets[symbol]['ask_price'] == 0:
            continue        
        aim_value = -Trade_value * _N(assets[symbol]['btc_diff'] / 0.01, 3)        
        if aim_value - assets[symbol]['ask_value'] >= Adjust_value and assets[symbol]['btc_diff'] > Min_diff and assets['USDT']['long_value'] - assets['USDT']['short_value'] <= 1.1 * Trade_value:
            Log('做多',symbol,'   aim_value:',aim_value,'   偏离平均:',assets[symbol]['btc_diff'])            
            trade(symbol, 'buy', aim_value - assets[symbol]['ask_value'])
        if aim_value - assets[symbol]['bid_value'] <= -Adjust_value and assets[symbol]['btc_diff'] < Max_diff and assets['USDT']['short_value'] - assets['USDT']['long_value'] <= 1.1 * Trade_value:
            Log('做空',symbol,'   aim_value:',aim_value,'   偏离平均:',assets[symbol]['btc_diff'])            
            trade(symbol, 'sell', -(aim_value - assets[symbol]['bid_value']))

def main():
    global RunTime
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused|Unknown")
    while True:
        RunTime = RuningTime()
        RunCommand() #捕获交互命令
        updateAccount() #更新账户和持仓
        updateTick() #行情
        stopLoss() #止损
        onTick() #策略逻辑部分
        updateStatus() #输出状态栏信息
        Sleep(Interval * 1000)


More

zhiwei1992 强!!!