Esempio n. 1
0
async def calcul_balance(account_manager):
    """
    计算做市商账户balance信息的函数:
    生成一个dataframe,包含各个账户的cash(ETH)和山寨币库存情况
    
    balance = await calcul_balance(account_manager)
    Input:
    account_manager:账户管理类
    Output:
    balance:做市商账户组的账户信息dataframe
    """
    # 登录账户并读取数据
    logger.info('"msg": "calcul_balance"')
    try:
        await account_manager.login()
    except:
        logger.error('"error": "Account Login Timeout!"')
        raise

    total_balance = await account_manager.total_balance()
    logger.info('"msg": "read balance done"')

    InventorySymbol = symbol.split('/')[0]  # 山寨币的symbol

    balance = pd.DataFrame(total_balance).T
    balance['cash_total'] = balance['ETH'].apply(lambda x: float(x['total']))
    balance['cash_free'] = balance['ETH'].apply(lambda x: float(x['free']))
    balance['Inventory_total'] = balance[InventorySymbol].apply(
        lambda x: float(x['total']))
    balance['Inventory_free'] = balance[InventorySymbol].apply(
        lambda x: float(x['free']))
    balance = balance[[
        'cash_total', 'cash_free', 'Inventory_total', 'Inventory_free'
    ]]
    return balance
Esempio n. 2
0
async def main():
    # 定义loop
    loop = asyncio.get_event_loop()
    # 登录账户
    logger.info('"msg": "init account"')
    all_account = [Account(clz=dex, **i) for i in ACCOUNTS
                   ]  # 注意,这里的登录方法用的是MMmarket名,需要检查是否一致(目前dex和dex_test是一致的)
    logger.info('"msg": "init account manager"')
    account_manager = AccountManager(all_account)
    # 起一个协程来接收benchmark的数据
    BM_ch = CurrentData("depth", benchmark, timeout=3, symbol=symbol_BM)
    BM2_ch = CurrentData("depth", benchmark2, timeout=3, symbol=symbol_BM)
    # benchmark频道的错误计数
    benchmarkDataCount = 0
    # 由推送数据驱动
    logger.info('"msg": "init sub"')
    async with Subscribe("depth", MMmarket, symbol) as MM_ch:
        logger.info(
            '"msg": "#################################This Round Start#################################"'
        )
        async for msg in MM_ch:
            try:
                logger.info(f'"data": "Latest raw data {cache._content[-1]}"')
                # 如果benchmark的timeout错误连续出现了benmarkDataCountMax次,则转而读取备用benchmark频道
                if benchmarkDataCount < benmarkDataCountMax:
                    logger.info(
                        f'"msg": "Try benchmark channel: {benchmarkDataCount+1} times"'
                    )
                    msg_BM = BM_ch.value
                    benchmarkDataCount = 0  # 从benchmark频道中成功读数就重置为0
                else:
                    logger.error(
                        f'"error": "There is someting wrong with benchmark channel, Try benchmark2 channel: {benchmarkDataCount-3} times, Please Check Channel ({benchmark})!"'
                    )
                    msg_BM = BM2_ch.value
                    benchmarkDataCount = 0  # 从benchmark备用频道中成功读数就重置为0
            except Exception as e:
                benchmarkDataCount = benchmarkDataCount + 1
                print(benchmarkDataCount)
                logger.info(f'"error": "Get Benchmark Data error {str(e)}"')
                continue

            asyncio.ensure_future(
                deal_with_data(msg, msg_BM, BestPrice_Master, cache,
                               account_manager, loop))
Esempio n. 3
0
async def SelfTrade(account_manager, balance, Fairvalue, spread, OB_RealTime):
    """
    处理自成交的函数:
    SelfTrade(account_manager, balance, Fairvalue, spread, OB_RealTime)
    调用这个函数,就会完成一次自成交操作
    
    Input:
    account_manager:账户管理的类
    balance:账户信息的dataframe
    Fairvalue:之前计算好的公平的中间价
    spread:之前计算好的最优买卖价差
    OB_RealTime:当前实时的ask1/bid1数据
    """
    # ----登录账户----
    try:
        await account_manager.login()
    except:
        logger.error('"error": "Account Login Timeout!"')
        raise
    # ----信息预处理----
    IfSelfTrade = 1  # 是否自成交的判断变量
    # 首先做一个判断,如果Fairvalue与当前的中间价差距超过max(2%, 2*spreadRatio_orderbook),则强制不产生自成交
    ask1_RT = OB_RealTime['ask1'][0]
    bid1_RT = OB_RealTime['bid1'][0]
    midP_orderbook = Fairvalue
    midP_RT = (ask1_RT + bid1_RT) / 2
    spreadRatio_orderbook = spread / Fairvalue
    if abs(midP_orderbook / midP_RT - 1) >= max(2 * 1e-2,
                                                2 * spreadRatio_orderbook):
        IfSelfTrade = 0  # 将IfSelfTrade设为0,即强制不进行自成交
        logger.info(
            f'"data": "No SelfTrade, Because Gap Too Large -- Market RealTime midP: {midP_RT} -- Orderbook midP: {midP_orderbook}"'
        )
    # balance1,所有slave账户按照库存总额排序,以此确定用哪个slave来成交
    balance1 = balance.sort_values('Inventory_total').reset_index()
    balance1 = balance1[balance1['index'] != 'Master']
    Slave_Cash_Total = balance1['cash_total'].sum()
    Slave_Inventory_Total = balance1['Inventory_total'].sum() * midP_orderbook
    Master_Cash_free = balance[balance.index == 'Master']['cash_free'][0]
    Master_Inventory_free = balance[
        balance.index == 'Master']['Inventory_free'][0] * midP_orderbook
    # 以slave账户总库存来确定自成交的方向--slave账户总山寨币库存低则slave买入,总现金库存低则slave卖出,其余情况随机
    # 以master账户可用来确定自成交方向--master账户山寨币可用低则slave卖出,现金可用低则slave买入,其余情况随机
    if (Slave_Cash_Total < Slave_Cash_Total_MIN) or (
            Master_Inventory_free < Master_Inventory_free_MIN):
        Direction = -1
    elif (Slave_Inventory_Total < Slave_Inventory_Total_MIN) or (
            Master_Cash_free < Master_Cash_free_MIN):
        Direction = 1
    else:
        Direction = int(round(np.random.uniform(0, 1), 0)) * 2 - 1
    logger.info(f'"data": "SelfTrade Direction: {Direction}"')
    logger.info(
        f'"data": "-- Slave_Cash_Total: {Slave_Cash_Total} -- Slave_Inventory_Total: {Slave_Inventory_Total}"'
    )
    logger.info(
        f'"data": "-- Master_Cash_free: {Master_Cash_free} -- Master_Inventory_free: {Master_Inventory_free}"'
    )
    # ----开始自成交操作(在IfSelfTrade==1的时候)----
    if IfSelfTrade == 1:
        # --首先,计算自成交的价格、量等信息--
        global InventoryWant2be
        global BestPrice_Master
        # 随机的交易量,满足条件:在区间(0.11, SelfTradeTotalMax)内
        SelfOrderTotal = 0
        while (SelfOrderTotal < 0.11 or SelfOrderTotal > SelfTradeTotalMax):
            SelfOrderTotal = np.random.exponential(SelfTradeTotalMax / 2)
        # 自成交单子的价格,靠近中间价,谨防被套利
        SelfBuyPrice = ask1_RT - 1 / 2 * np.random.uniform(0.95, 1.05) * (
            ask1_RT - bid1_RT)  # 自成交的买单为当前的中间价附近
        SelfSellPrice = bid1_RT + 1 / 2 * np.random.uniform(0.95, 1.05) * (
            ask1_RT - bid1_RT)  # 自成交的卖单为当前中间价附近
        # --然后,发出自成交的单子,并更新InvestoryWant2be--
        randNum = np.random.uniform(0, 1)  # 随机变量来确定交易量是否取整
        if Direction == 1:
            AccountName = balance1.iloc[0]['index']  # 库存最小的slave执行买入
            SelfOrderType = 'BuyOrder'
            SelfOrderPrice = SelfBuyPrice
            if randNum < 1 / 2:  # 依据一个随机量来确定:(1)下单量取整;(2)不取整
                SelfVolume = SelfOrderTotal / SelfOrderPrice
                if SelfVolume >= 10:
                    SelfVolume = round(SelfVolume, 0) + 1
                else:
                    SelfVolume = round(SelfVolume, 1) + 0.1
            else:
                SelfVolume = SelfOrderTotal / SelfOrderPrice
            SelfOrder1 = await create_order(account_manager, 'Master', 'Sell',
                                            SelfVolume, SelfOrderPrice, 5)
            SelfOrder2 = await create_order(account_manager, AccountName,
                                            'Buy', SelfVolume, SelfOrderPrice,
                                            1)
            InventoryWant2be = InventoryWant2be - SelfVolume * TakerOrderCost  # 山寨币买方为吃单,用Taker费率计算交易费用,再更新合宜库存量
        elif Direction == -1:
            AccountName = balance1.iloc[-1]['index']  # 库存最大的slave执行卖出
            SelfOrderType = 'SellOrder'
            SelfOrderPrice = SelfSellPrice
            if randNum < 1 / 2:  # 依据一个随机量来确定:(1)下单量取整;(2)不取整
                SelfVolume = round(SelfOrderTotal / SelfOrderPrice, 0) + 1
            else:
                SelfVolume = SelfOrderTotal / SelfOrderPrice
            SelfOrder1 = await create_order(account_manager, 'Master', 'Buy',
                                            SelfVolume, SelfOrderPrice, 5)
            SelfOrder2 = await create_order(account_manager, AccountName,
                                            'Sell', SelfVolume, SelfOrderPrice,
                                            1)
            InventoryWant2be = InventoryWant2be - SelfVolume * MakerOrderCost  # 山寨币买方为挂单,用Maker费率计算交易费用,再更新合宜库存量
        logger.info(
            f'"data": "--SelfTradeOccurs: {AccountName} send a {SelfOrderType} at {SelfOrderPrice} with (amount,total):({SelfVolume},{SelfOrderTotal}), Update InventoryWant2be({InventoryWant2be})--"'
        )
Esempio n. 4
0
async def send_order(account_manager, balance, orderbook):
    """
    根据计算的orderbook发送山寨币订单的函数:
    send_order(account_manager,balance,orderbook)
    依据计算的orderbook向dex发送订单簿
    (**)优化方向:如何自适应orderbook的档位(比如,想挂15个档位)?
    
    Input:
    account_manager:账户管理的类
    balance:账户信息的dataframe
    orderbook:之前计算好的想要达到的orderbook
    """
    # 登录账户
    logger.info('"msg": "send_order start"')
    try:
        await account_manager.login()
    except:
        logger.error('"error": "Account Login Timeout!"')
        raise
    # ----判断Master账户能不能提交orderbook----
    balance_Master = balance.reset_index()
    balance_Master = balance_Master[balance_Master['index'] == 'Master']
    ETH_all_Master = balance_Master['cash_total'][0]  # Master的账户中ETH总额
    Inventory_all_Master = balance_Master['Inventory_total'][
        0]  # Master的账户中山寨币总额
    orderbook_Master = orderbook.copy()
    orderbook_Master[
        'bid_cash'] = orderbook_Master['bid'] * orderbook_Master['bidS']
    bid_all_Master = orderbook_Master['bid_cash'].sum()  # Master要挂出的所有买单之和
    ask_all_Master = orderbook_Master['askS'].sum()  # Master要挂出的所有卖单之和
    if (bid_all_Master >= ETH_all_Master) or (ask_all_Master >=
                                              Inventory_all_Master):
        logger.error(
            f"error: Master Account have No Enough ETH or Inventory! Please Check!"
        )
    # ----开始执行订单操作----
    # --先撤销Master的所有订单--
    NowTimeStamp = f'{int(time.time()*1000)}'
    Master_cancel_all = await account_manager.Master.cancel_all_orders(
        symbol, NowTimeStamp)
    # --再依据orderbook下单--
    # bid1和ask1先下单下去,其余的orderbook部分一起下
    logger.info('"msg": "place order"')
    global ISOrderbookUpdateNotOK  # 如果没有挂单成功,那么下一轮循环继续挂单
    ISOrderbookUpdateNotOK = 0
    try:
        try:
            bid1 = await create_order(account_manager, 'Master', 'Buy',
                                      orderbook['bidS'][0],
                                      orderbook['bid'][0])
        except Exception as e:
            logger.error(
                f'"error": "place order bid1 {bid1} error :[{type(e)}]  {e}"')
            raise
        else:
            logger.info(f'"msg": "place order bid1 {bid1}"')
        try:
            ask1 = await create_order(account_manager, 'Master', 'Sell',
                                      orderbook['askS'][0],
                                      orderbook['ask'][0])
        except Exception as e:
            logger.error(
                f'"error": "place order ask1 {ask1} error :[{type(e)}]  {e}"')
            raise
        else:
            logger.info(f'"msg": "place order ask1 {ask1}"')
        bid2 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][1], orderbook['bid'][1])
        logger.info(
            f""""msg": "place order bid2: orderId is {bid2['order']['orderId']}" """
        )
        ask2 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][1], orderbook['ask'][1])
        logger.info(
            f""""msg": "place order ask2: orderId is {ask2['order']['orderId']}" """
        )
        bid3 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][2], orderbook['bid'][2])
        logger.info(
            f""""msg": "place order bid3: orderId is {bid3['order']['orderId']}" """
        )
        ask3 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][2], orderbook['ask'][2])
        logger.info(
            f""""msg": "place order ask3: orderId is {ask3['order']['orderId']}" """
        )
        bid4 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][3], orderbook['bid'][3])
        logger.info(
            f""""msg": "place order bid4: orderId is {bid4['order']['orderId']}" """
        )
        ask4 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][3], orderbook['ask'][3])
        logger.info(
            f""""msg": "place order ask4: orderId is {ask4['order']['orderId']}" """
        )
        bid5 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][4], orderbook['bid'][4])
        logger.info(
            f""""msg": "place order bid5: orderId is {bid5['order']['orderId']}" """
        )
        ask5 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][4], orderbook['ask'][4])
        logger.info(
            f""""msg": "place order ask5: orderId is {ask5['order']['orderId']}" """
        )
        bid6 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][5], orderbook['bid'][5])
        logger.info(
            f""""msg": "place order bid6: orderId is {bid6['order']['orderId']}" """
        )
        ask6 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][5], orderbook['ask'][5])
        logger.info(
            f""""msg": "place order ask6: orderId is {ask6['order']['orderId']}" """
        )
        bid7 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][6], orderbook['bid'][6])
        logger.info(
            f""""msg": "place order bid7: orderId is {bid7['order']['orderId']}" """
        )
        ask7 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][6], orderbook['ask'][6])
        logger.info(
            f""""msg": "place order ask7: orderId is {ask7['order']['orderId']}" """
        )
        bid8 = await create_order(account_manager, 'Master', 'Buy',
                                  orderbook['bidS'][7], orderbook['bid'][7])
        logger.info(
            f""""msg": "place order bid8: orderId is {bid8['order']['orderId']}" """
        )
        ask8 = await create_order(account_manager, 'Master', 'Sell',
                                  orderbook['askS'][7], orderbook['ask'][7])
        logger.info(
            f""""msg": "place order ask8: orderId is {ask8['order']['orderId']}" """
        )
    except Exception as e:
        ISOrderbookUpdateNotOK = 1
        logger.info('"msg": "--Warning: Orderbook Update Not Scucess"')
    # --记录一下Master自己挂出来的bid1和ask1,更新到一个缓存数据结构BestPrice_Master--
    global BestPrice_Master
    ask1_Master = round(orderbook['ask'][0], 8)
    bid1_Master = round(orderbook['bid'][0], 8)
    BestPrice_Master.append([ask1_Master, bid1_Master])
    midP_Master = round((ask1_Master + bid1_Master) / 2, 8)
    logger.info(
        f'"data": "Master place ask1({ask1_Master}) and bid1({bid1_Master}), midP_Master is {midP_Master}"'
    )
    # --最后更新一下orderbookUpdateCount--
    # (注意)这里放在最后,是因为必须有了orderbook下单才算真的做完了一轮
    global orderbookUpdateCount
    orderbookUpdateCount = orderbookUpdateCount + 5  # 一旦orderbook出现了Update,则加快自成交(让orderbookUpdateCount增加)
Esempio n. 5
0
async def create_order(account_manager,
                       Account,
                       BuyorSell,
                       amount,
                       price,
                       expire=86400):
    """
    产生山寨币订单的函数:
    order = await create_order(account_manager,Account,BuyorSell,amount,price)
    根据输入参数情况,向dex输送订单
    (**)优化方向:如何自适应账户数目?
    
    Input:
    Account:账户名称
    BuyorSell:买单还是卖单(只能是Buy或者Sell,注意大小写)
    amount:下单量
    price:下单价格
    Output:
    order:订单类
    """
    try:
        if BuyorSell == 'Buy' or BuyorSell == 'Sell':
            if Account == 'Master':
                if BuyorSell == 'Buy':
                    order = await account_manager.Master.createLimitBuyOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
                else:
                    order = await account_manager.Master.createLimitSellOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
            elif Account == 'Slave1':
                if BuyorSell == 'Buy':
                    order = await account_manager.Slave1.createLimitBuyOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
                else:
                    order = await account_manager.Slave1.createLimitSellOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
            elif Account == 'Slave2':
                if BuyorSell == 'Buy':
                    order = await account_manager.Slave2.createLimitBuyOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
                else:
                    order = await account_manager.Slave2.createLimitSellOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
            elif Account == 'Slave3':
                if BuyorSell == 'Buy':
                    order = await account_manager.Slave3.createLimitBuyOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
                else:
                    order = await account_manager.Slave3.createLimitSellOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
            elif Account == 'Slave4':
                if BuyorSell == 'Buy':
                    order = await account_manager.Slave4.createLimitBuyOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
                else:
                    order = await account_manager.Slave4.createLimitSellOrder(
                        symbol,
                        round(amount, 3),
                        round(price, 8),
                        expire=expire)
            else:
                logger.error(
                    f'"error": "error: def create_order just considers 5 Account"'
                )
        else:
            logger.error(f'"error": "error: BuyorSell must be Buy or Sell"')
        return order
    except:
        traceback.print_exc()
        raise
Esempio n. 6
0
def data_transform_His(cache):
    """
    处理历史数据,benchmark和dex的值都可能要转换
    
    OBdf = data_transform_His(cache)
    Input:
    cache:缓存的过去一段时间的历史数据
    Ouput:
    OBdf:一个dataframe,根据条件对benchmark和dex的历史价格转换,然后获得的一个ask1、bid1、ask1_BM、bid1_BM四列数的表
    """
    # --取数据--
    OBdf = cache.to_dataframe()
    # --历史orderbook数据不够的报警(可能是数据库的bug)--
    if len(OBdf) < ((TimeWindow * 12) * 0.5):
        logger.error(
            f'"error": "Hisdata OBdf has {len(OBdf)} rows, TimeWindow should have {TimeWindow*12} rows, Please Check DataBase!"'
        )
    # --benchmark数据--
    # 以ETH/USDT作为benchmark,需要将ETH/USDT转换为一个模拟价格:(1-b)*山寨币初始价格+(山寨币初始价格*b/ETH初始价格)*ETH价格
    ETH2BMPrice = b * Price0 / ETH0  # 转换系数
    if IfUsingETHasBM == 1:
        OBdf['ask1_BM'] = (1 - b) * Price0 + ETH2BMPrice * OBdf['ask1_BM']
        OBdf['bid1_BM'] = (1 - b) * Price0 + ETH2BMPrice * OBdf['bid1_BM']
    # --dex数据--
    # 不用历史数据时,需要构造一个虚拟的山寨币历史数据,使得历史数据满足spread0、PDiff0
    if IfNotUsingHisData == 1:
        OBdf['midP0'] = (OBdf['ask1_BM'] + OBdf['bid1_BM']
                         ) / 2 + PDiff0  # 模拟的中间价:benchmark的中间价加上给定价差PDiff0
        OBdf['spread0'] = OBdf[
            'midP0'] * spreadRatio0  # 模拟的spread0:中间价乘以给定的价差比例spreadRatio0
        OBdf['ask1_rand'] = np.random.uniform(
            -1 / 2, 1 / 2, len(OBdf))  # 计算ask1和bid1,加上了一点随机量
        OBdf['bid1_rand'] = np.random.uniform(-1 / 2, 1 / 2, len(OBdf))
        OBdf['ask1'] = OBdf['midP0'] + (1 / 2 +
                                        OBdf['ask1_rand']) * OBdf['spread0']
        OBdf['bid1'] = OBdf['midP0'] - (1 / 2 +
                                        OBdf['bid1_rand']) * OBdf['spread0']
        OBdf = OBdf[['ask1', 'bid1', 'ask1_BM', 'bid1_BM']]
    # --剔除明显错误数据(3个标准差以外的值删除)--
    OBdf_mean = OBdf.mean()
    OBdf_std = OBdf.std()
    bid1_sup, bid1_inf = OBdf_mean['bid1'] + 3 * OBdf_std['bid1'], OBdf_mean[
        'bid1'] - 3 * OBdf_std['bid1']
    ask1_sup, ask1_inf = OBdf_mean['ask1'] + 3 * OBdf_std['ask1'], OBdf_mean[
        'ask1'] - 3 * OBdf_std['ask1']
    bid1_BM_sup, bid1_BM_inf = OBdf_mean['bid1_BM'] + 3 * OBdf_std[
        'bid1_BM'], OBdf_mean['bid1_BM'] - 3 * OBdf_std['bid1_BM']
    ask1_BM_sup, ask1_BM_inf = OBdf_mean['ask1_BM'] + 3 * OBdf_std[
        'ask1_BM'], OBdf_mean['ask1_BM'] - 3 * OBdf_std['ask1_BM']
    OBdf = OBdf[(bid1_inf < OBdf['bid1']) & (OBdf['bid1'] < bid1_sup) &
                (ask1_inf < OBdf['ask1']) &
                (OBdf['ask1'] < ask1_sup)]  # 自己交易所的筛选
    OBdf = OBdf[(bid1_BM_inf < OBdf['bid1_BM']) &
                (OBdf['bid1_BM'] < bid1_BM_sup) &
                (ask1_BM_inf < OBdf['ask1_BM']) &
                (OBdf['ask1_BM'] < ask1_BM_sup)]  # benchmark交易所的筛选

    logger.info(
        f'"data": "Get Hisdata OBdf, the last row is: {OBdf.iloc[-1]}"')

    return OBdf