# auto generated by update_py.py

import ctypes
import datetime

from tlclient.linker.constant import FIST_NAME_MAX_LIMIT
from tlclient.linker.timer import Timer
from tlclient.linker.utility import nano_to_str
from tlclient.trader.constant import (MODULE_ERR_MSG_LENGTH, MODULE_ORDERREF_LENGTH,
                             MODULE_SOURCE_LENGTH, MODULE_TICKER_LENGTH,
                             MODULE_TRADEID_LENGTH, MODULE_TRADINGDAY_LENGTH,
                             AssetType, Direction, ExchangeID, ExecRole,
                             MarginMode, OffsetFlag, OrderStatus, OrderType,
                             PosiDirection)


class OrderBasic(ctypes.Structure):
    _fields_ = [
        ('exchange', ctypes.c_short),
        ('ticker', ctypes.c_char * MODULE_TICKER_LENGTH),
        ('source', ctypes.c_char * MODULE_SOURCE_LENGTH),
        ('price', ctypes.c_double),
        ('volume', ctypes.c_double),
        ('asset_type', ctypes.c_short),
        ('order_type', ctypes.c_short),
        ('direction', ctypes.c_short),
        ('offset_flag', ctypes.c_short),
        ('margin_mode', ctypes.c_short),
        ('lever_rate', ctypes.c_int64),
    ]

    def __str__(self):
        return '<ord-{} exch={} tkr={} px={} vol={} type={} dir={}>'.format(
            self.order_id, ExchangeID.read(self.exchange), self.ticker, self.price, self.volume,
            OrderType.read(self.order_type), Direction.read(self.direction)
        )

    def to_dict(self):
        return {
            'exchange': ExchangeID.read(self.exchange),
            'ticker': self.ticker.decode(),
            'source': self.source.decode(),
            'price': self.price,
            'volume': self.volume,
            'asset_type': AssetType.read(self.asset_type),
            'order_type': self.order_type,
            'direction': Direction.read(self.direction),
            'offset_flag': OffsetFlag.read(self.offset_flag),
            'margin_mode': MarginMode.read(self.margin_mode),
            'lever_rate': self.lever_rate,
        }

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "exchange": self.exchange,
                "ticker": self.ticker,
                "source": self.source,
                'asset_type': self.asset_type,
                "order_type": self.order_type,
                "direction": self.direction,
                "offset_flag": self.offset_flag,
                "margin_mode": self.margin_mode,
                "lever_rate": self.lever_rate,
            },
            "time": Timer.datetime(),
            "fields": {
                "price": self.price,
                "volume": self.volume,
            }
        }


class ReqOrderInsert(OrderBasic):
    _fields_ = [
        ('tg_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
        ('parent_id', ctypes.c_int64),
        ('order_id', ctypes.c_int64),
        ('order_ref', ctypes.c_char * MODULE_ORDERREF_LENGTH),
        ('client_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
    ]

    def __str__(self):
        return '<ord-{} pid={} tg={} exch={} ref={} tkr={} px={} vol={} type={} dir={}>'.format(
            self.order_id, self.parent_id, self.tg_name, ExchangeID.read(self.exchange), self.order_ref, self.ticker, self.price, self.volume,
            OrderType.read(self.order_type), Direction.read(self.direction)
        )

    def to_dict(self):
        return dict(OrderBasic.to_dict(self), **{
            'tg_name': self.tg_name.decode(),
            'parent_id': self.parent_id,
            'order_id': self.order_id,
            'order_ref': self.order_ref.decode(),
            'client_name': self.client_name.decode(),
        })

    def to_influx(self):
        return {
            "measurement": None,
            "tags": dict(OrderBasic.to_influx(self)['tags'], **{
                "tg_name": self.tg_name,
                "parent_id": self.parent_id,
                "order_id": self.order_id,
                "order_ref": self.order_ref,
                "client_name": self.client_name,
            }),
            "time": Timer.datetime(),
            "fields": OrderBasic.to_influx(self)['fields']
        }


class RspOrderInsert(ctypes.Structure):
    _fields_ = [
        ('order_id', ctypes.c_int64),
        ('order_ref', ctypes.c_char * MODULE_ORDERREF_LENGTH),
        ('err_id', ctypes.c_int),
        ('err_msg', ctypes.c_char * MODULE_ERR_MSG_LENGTH),
    ]

    def __str__(self):
        return '<roi oid={} ref={} err_id={} err_msg={}>'.format(
            self.order_id, self.order_ref, self.err_id, self.err_msg
        )

    def to_dict(self):
        return {
            'order_id': self.order_id,
            'order_ref': self.order_ref.decode(),
            'err_id': self.err_id,
            'err_msg': self.err_msg.decode(),
        }

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "order_id": self.order_id,
                "order_ref": self.order_ref,
                "err_id": self.err_id,
                "err_msg": self.err_msg,
            },
            "time": Timer.datetime(),
            "fields": {
            }
        }


class ReqOrderCancel(ctypes.Structure):
    _fields_ = [
        ('tg_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
        ('req_id', ctypes.c_int64),
        ('order_id', ctypes.c_int64),
    ]

    def __str__(self):
        return '<oc oid={} rid={} tg_name={}>'.format(
            self.order_id, self.req_id, self.tg_name
        )

    def to_dict(self):
        return {
            'tg_name': self.tg_name.decode(),
            'req_id': self.req_id,
            'order_id': self.order_id,
        }

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "tg_name": self.tg_name,
                "req_id": self.req_id,
                "order_id": self.order_id,
            },
            "time": Timer.datetime(),
            "fields": {
            }
        }


class RspOrderCancel(ctypes.Structure):
    _fields_ = [
        ('req_id', ctypes.c_int64),
        ('order_id', ctypes.c_int64),
        ('order_ref', ctypes.c_char * MODULE_ORDERREF_LENGTH),
        ('err_id', ctypes.c_int),
        ('err_msg', ctypes.c_char * MODULE_ERR_MSG_LENGTH),
    ]

    def __str__(self):
        return '<roc rid={} oid={} ref={} eid={} err={}>'.format(
            self.req_id, self.order_id, self.order_ref, self.err_id, self.err_msg
        )

    def to_dict(self):
        return {
            'req_id': self.req_id,
            'order_id': self.order_id,
            'order_ref': self.order_ref.decode(),
            'err_id': self.err_id,
            'err_msg': self.err_msg.decode(),
        }

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "req_id": self.req_id,
                "order_id": self.order_id,
                "order_ref": self.order_ref,
                "err_id": self.err_id,
                "err_msg": self.err_msg,
            },
            "time": Timer.datetime(),
            "fields": {
            }
        }


class RtnOrder(ctypes.Structure):
    _fields_ = [
        ('tg_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
        ('exchange', ctypes.c_short),
        ('ticker', ctypes.c_char * MODULE_TICKER_LENGTH),
        ('asset_type', ctypes.c_short),
        ('order_type', ctypes.c_short),
        ('order_status', ctypes.c_short),
        ('volume_traded', ctypes.c_double),
        ('front_id', ctypes.c_int),
        ('session_id', ctypes.c_int),
        ('order_id', ctypes.c_int64),
        ('order_ref', ctypes.c_char * MODULE_ORDERREF_LENGTH),
    ]

    def __str__(self):
        return '<o oid={} ref={} tg={} exch={} ass={} tkr={} tp={} status={} traded={}>'.format(
            self.order_id, self.order_ref, self.tg_name, ExchangeID.read(self.exchange), AssetType.read(self.asset_type),
            self.ticker, OrderType.read(self.order_type), OrderStatus.read(self.order_status), self.volume_traded
        )

    def to_dict(self):
        return {
            'tg_name': self.tg_name.decode(),
            'exchange': ExchangeID.read(self.exchange),
            'ticker': self.ticker.decode(),
            'asset_type': AssetType.read(self.asset_type),
            'order_type': self.order_type,
            'order_status': OrderStatus.read(self.order_status),
            'volume_traded': self.volume_traded,
            'front_id': self.front_id,
            'session_id': self.session_id,
            'order_id': self.order_id,
            'order_ref': self.order_ref.decode(),
        }

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "tg_name": self.tg_name,
                "exchange": self.exchange,
                "ticker": self.ticker,
                'asset_type': self.asset_type,
                'order_type': self.order_type,
                "order_status": self.order_status,
                "front_id": self.front_id,
                "session_id": self.session_id,
                "order_id": self.order_id,
                "order_ref": self.order_ref,
            },
            "time": Timer.datetime(),
            "fields": {
                "volume_traded": self.volume_traded,
            }
        }


class RtnTrade(ctypes.Structure):
    _fields_ = [
        ('tg_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
        ('exchange', ctypes.c_short),
        ('ticker', ctypes.c_char * MODULE_TICKER_LENGTH),
        ('price', ctypes.c_double),
        ('volume', ctypes.c_double),
        ('commission', ctypes.c_double),
        ('exec_role', ctypes.c_short),
        ('asset_type', ctypes.c_short),
        ('order_type', ctypes.c_short),
        ('direction', ctypes.c_short),
        ('offset_flag', ctypes.c_short),
        ('trade_id', ctypes.c_char * MODULE_TRADEID_LENGTH),
        ('trade_time', ctypes.c_int64),
        ('trading_day', ctypes.c_char * MODULE_TRADINGDAY_LENGTH),
        ('order_id', ctypes.c_int64),
        ('order_ref', ctypes.c_char * MODULE_ORDERREF_LENGTH),
    ]

    def __str__(self):
        return '<t tid={} oid={} ref={} tg={} exch={} ass={} tkr={} dir={} tp={} px={} vol={} comm={} t={}>'.format(
            self.trade_id, self.order_id, self.order_ref, self.tg_name, ExchangeID.read(self.exchange), AssetType.read(self.asset_type),
            self.ticker, Direction.read(self.direction), OrderType.read(self.order_type), self.price, self.volume, self.commission,
            datetime.datetime.fromtimestamp(self.trade_time / 1e9).strftime('%Y-%m-%d %H:%M:%S')
        )

    def to_dict(self):
        return {
            'tg_name': self.tg_name.decode(),
            'exchange': ExchangeID.read(self.exchange),
            'ticker': self.ticker.decode(),
            'price': self.price,
            'volume': self.volume,
            'commission': self.commission,
            'exec_role': ExecRole.read(self.exec_role),
            'asset_type': AssetType.read(self.asset_type),
            'order_type': self.order_type,
            'direction': Direction.read(self.direction),
            'offset_flag': OffsetFlag.read(self.offset_flag),
            'trade_id': self.trade_id.decode(),
            'trade_time': self.trade_time,
            'trading_day': self.trading_day.decode(),
            'order_id': self.order_id,
            'order_ref': self.order_ref.decode(),
        }

    @staticmethod
    def from_dict(d=None):
        d = d or None

        t = RtnTrade()
        t.tg_name = d.get('tg_name', '').encode()
        t.exchange = ExchangeID.parse(d.get('exchange', ExchangeID.NOT_AVAILABLE))
        t.ticker = d.get('ticker', '').encode()
        t.price = d.get('price', -1)
        t.volume = d.get('volume', -1)
        t.commission = d.get('commission', -1)
        t.exec_role = ExecRole.parse(d.get('exec_role', ExecRole.NOT_AVAILABLE))
        t.asset_type = AssetType.parse(d.get('asset_type', AssetType.NOT_AVAILABLE))
        t.order_type = d.get('order_type', OrderType.NOT_AVAILABLE)
        t.direction = Direction.parse(d.get('direction', Direction.NOT_AVAILABLE))
        t.offset_flag = OffsetFlag.parse(d.get('offset_flag', OffsetFlag.NOT_AVAILABLE))
        t.trade_id = d.get('trade_id', '').encode()
        t.trade_time = d.get('trade_time', -1)
        t.trading_day = d.get('trading_day', '').encode()
        t.order_id = d.get('order_id', -1)
        t.order_ref = d.get('order_ref', '').encode()

        return t

    def to_influx(self):
        return {
            "measurement": "RtnTrade",
            "tags": {
                "tg_name": self.tg_name,
                "exchange": self.exchange,
                "ticker": self.ticker,
                'exec_role': self.exec_role,
                'asset_type': self.asset_type,
                "order_type": self.order_type,
                "direction": self.direction,
                "offset_flag": self.offset_flag,
                "trade_id": self.trade_id,
                "trading_day": self.trading_day,
                "order_id": self.order_id,
                "order_ref": self.order_ref,
            },
            "time": Timer.nano_to_datetime(self.trade_time),
            "fields": {
                "price": self.price,
                "volume": self.volume,
                'commission': self.commission,
            }
        }


class ReqBasic(ctypes.Structure):
    _fields_ = [
        ('req_id', ctypes.c_int64),
        ('tg_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
        ('client_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
    ]

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "req_id": self.req_id,
                "tg_name": self.tg_name,
                "client_name": self.client_name,
            },
            "time": Timer.datetime(),
            "fields": {
            }
        }


class ReqPosition(ReqBasic):
    _fields_ = [
    ]

    def to_influx(self):
        return {
            "measurement": None,
            "tags": ReqBasic.to_influx(self)['tags'],
            "time": Timer.datetime(),
            "fields": ReqBasic.to_influx(self)['fields']
        }


class ReqAccount(ReqBasic):
    _fields_ = [
    ]

    def to_influx(self):
        return {
            "measurement": None,
            "tags": ReqBasic.to_influx(self)['tags'],
            "time": Timer.datetime(),
            "fields": ReqBasic.to_influx(self)['fields']
        }


class ReqOrderInfo(ctypes.Structure):
    _fields_ = [
        ('order_id', ctypes.c_int64),
        ('client_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
    ]

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "order_id": self.order_id,
                "client_name": self.client_name,
            },
            "time": Timer.datetime(),
            "fields": {
            }
        }


class RspOrderInfo(ReqOrderInsert):
    _fields_ = [
        ('err_id', ctypes.c_int),
        ('err_msg', ctypes.c_char * MODULE_ERR_MSG_LENGTH),
        ('cancel_err_id', ctypes.c_int),
        ('cancel_err_msg', ctypes.c_char * MODULE_ERR_MSG_LENGTH),
        ('order_status', ctypes.c_short),
        ('volume_traded', ctypes.c_double),
    ]

    def __str__(self):
        return '<ord-{} tg={} exch={} ref={} tkr={} px={} vol={} type={} dir={} status={} vol_traded={}>'.format(
            self.order_id, self.tg_name, ExchangeID.read(self.exchange), self.order_ref, self.ticker, self.price, self.volume,
            OrderType.read(self.order_type), Direction.read(self.direction), OrderStatus.read(self.order_status), self.volume_traded
        )

    def to_dict(self):
        return dict(ReqOrderInsert.to_dict(self), **{
            'err_id': self.err_id,
            'err_msg': self.err_msg.decode(),
            'cancel_err_id': self.cancel_err_id,
            'cancel_err_msg': self.cancel_err_msg.decode(),
            'order_status': self.order_status,
            'volume_traded': self.volume_traded,
        })

    def to_influx(self):
        return {
            "measurement": None,
            "tags": dict(ReqOrderInsert.to_influx(self)['tags'], **{
                "err_id": self.err_id,
                "err_msg": self.err_msg,
                "cancel_err_id": self.cancel_err_id,
                "cancel_err_msg": self.cancel_err_msg,
                "order_status": self.order_status,
                "volume_traded": self.volume_traded,
            }),
            "time": Timer.datetime(),
            "fields": ReqOrderInsert.to_influx(self)['fields']
        }


class ReqActiveOrders(ReqBasic):
    _fields_ = [
    ]

    def to_influx(self):
        return {
            "measurement": None,
            "tags": ReqBasic.to_influx(self)['tags'],
            "time": Timer.datetime(),
            "fields": ReqBasic.to_influx(self)['fields']
        }


class ReqHistoryTrades(ReqBasic):
    _fields_ = [
    ]

    def to_influx(self):
        return {
            'measurement': None,
            'tags': ReqBasic.to_influx(self)['tags'],
            "time": Timer.datetime(),
            "fields": ReqBasic.to_influx(self)['fields']
        }


class RspAccount(ctypes.Structure):
    _fields_ = [
        ('tg_name', ctypes.c_char * FIST_NAME_MAX_LIMIT),
        ('commission', ctypes.c_double),
        ('available', ctypes.c_double),
        ('withdrawable', ctypes.c_double),
        ('market_value', ctypes.c_double),
        ('cur_margin', ctypes.c_double),
        ('reserve', ctypes.c_double),
    ]

    def __str__(self):
        return '<a tg={} commis={} avail={} withd={} marketV={} curMarr={} reserve={}>'.format(
            self.tg_name, self.commission, self.available, self.withdrawable,
            self.market_value, self.cur_margin, self.reserve
        )

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "tg_name": self.tg_name,
            },
            "time": Timer.datetime(),
            "fields": {
                "commission": self.commission,
                "available": self.available,
                "withdrawable": self.withdrawable,
                "market_value": self.market_value,
                "cur_margin": self.cur_margin,
                "reserve": self.reserve,
            }
        }

    def to_dict(self):
        return {
            'tg_name': self.tg_name.decode(),
            "commission": self.commission,
            "available": self.available,
            "withdrawable": self.withdrawable,
            "market_value": self.market_value,
            "cur_margin": self.cur_margin,
            "reserve": self.reserve,
        }


class PositionInfo:

    # init from a dict (parsed from json)
    def __init__(self, d=None):
        d = d or {}
        self.exchange = ExchangeID.parse(d.get('exchange'))
        self.ticker = d.get('ticker')
        self.source = d.get('source')
        self.margin_mode = MarginMode.parse(d.get('margin_mode'))
        self.asset_type = AssetType.parse(d.get('asset_type'))
        self.posi_direction = PosiDirection.parse(d.get('posi_direction'))
        self.position = d.get('position')
        self.yd_position = d.get('yd_position')
        self.position_cost = d.get('position_cost')
        self.frozen = d.get('frozen')
        self.available = d.get('available')
        self.borrowed = d.get('borrowed')
        self.interest = d.get('interest')
        self.liquidation_price = d.get('liquidation_price')
        self.equity = d.get('equity')
        self.risk_rate = d.get('risk_rate')
        self.pnl = d.get('pnl')
        self.realized_pnl = d.get('realized_pnl')
        self.unrealized_pnl = d.get('unrealized_pnl')

    def __str__(self):
        return '<pos-{}-{} tkr={} src={} dir={} mm={} pos={} ydpos={} cost={} frz={} avail={} brw={} i={} lpx={} eqt={} rr={} pnl={} | {} | {}>'.format(
            ExchangeID.read(self.exchange), AssetType.read(self.asset_type), self.ticker, self.source,
            PosiDirection.read(self.posi_direction), MarginMode.read(self.margin_mode), self.position, self.yd_position, self.position_cost,
            self.frozen, self.available, self.borrowed, self.interest, self.liquidation_price, self.equity, self.risk_rate,
            self.pnl, self.realized_pnl, self.unrealized_pnl,
        )

    def to_influx(self, dt=None):
        if dt is None:
            dt = Timer.datetime()
        return {
            "measurement": "PositionInfo",
            "tags": {
                "exchange": ExchangeID.read(self.exchange),
                "ticker": self.ticker,
                "source": self.source,
                "margin_mode": MarginMode.read(self.margin_mode),
                "asset_type": AssetType.read(self.asset_type),
                "posi_direction": PosiDirection.read(self.posi_direction),
            },
            "time": dt,
            "fields": {
                "position": float(self.position) if self.position is not None else None,
                "yd_position": float(self.yd_position) if self.yd_position else None,
                "position_cost": float(self.position_cost) if self.position_cost is not None else None,
                "frozen": float(self.frozen) if self.frozen is not None else None,
                "available": float(self.available) if self.available is not None else None,
                "borrowed": float(self.borrowed) if self.borrowed is not None else None,
                "interest": float(self.interest) if self.interest is not None else None,
                "liquidation_price": float(self.liquidation_price) if self.liquidation_price is not None else None,
                "equity": float(self.equity) if self.equity is not None else None,
                "risk_rate": float(self.risk_rate) if self.risk_rate is not None else None,
                "pnl": float(self.pnl) if self.pnl is not None else None,
                "realized_pnl": float(self.realized_pnl) if self.realized_pnl is not None else None,
                "unrealized_pnl": float(self.unrealized_pnl) if self.unrealized_pnl is not None else None,
            }
        }

    def to_dict(self):
        return {
            'exchange': ExchangeID.read(self.exchange),
            'ticker': self.ticker,
            'source': self.source,
            'margin_mode': MarginMode.read(self.margin_mode),
            'asset_type': AssetType.read(self.asset_type),
            'posi_direction': PosiDirection.read(self.posi_direction),
            'position': self.position,
            'yd_position': self.yd_position,
            'position_cost': self.position_cost,
            'frozen': self.frozen,
            'available': self.available,
            'borrowed': self.borrowed,
            'interest': self.interest,
            'liquidation_price': self.liquidation_price,
            'equity': self.equity,
            'risk_rate': self.risk_rate,
            'pnl': self.pnl,
            'realized_pnl': self.realized_pnl,
            'unrealized_pnl': self.unrealized_pnl,
        }

    def to_kdb(self, dt):
        d = dt.date()
        t = dt.time()
        return [
            d, t, ExchangeID.read(self.exchange), self.ticker.decode("utf-8"), self.source,
            MarginMode.read(self.margin_mode), AssetType.read(self.asset_type), PosiDirection.read(self.posi_direction),
            self.position, self.yd_position, self.frozen, self.available, self.borrowed, self.interest,
            self.liquidation_price, self.equity, self.risk_rate, self.pnl, self.realized_pnl, self.unrealized_pnl,
        ]


class RspPosition:

    # init from a dict (parsed from json)
    def __init__(self, d=None):
        d = d or {}
        self.tg_name = d.get('tg_name')
        self.positions = [PositionInfo(item_d) for item_d in d.get('positions', [])]

    def push_back(self, pos_info):
        self.positions.append(pos_info)

    def size(self):
        return len(self.positions)

    def get(self, idx, default_value=None):
        if idx < self.size() and idx >= 0:
            return self.positions[idx]
        return default_value

    def __str__(self):
        s = '<p tg={} count={}\n'.format(self.tg_name, len(self.positions))
        for pos in self.positions:
            s += '\t' + str(pos) + '\n'
        s += '>'
        return s

    @staticmethod
    def get_content_obj():
        return PositionInfo

    def to_influx(self):
        dt = Timer.datetime()
        return [info.to_influx(dt) for info in self.positions]

    def to_dict(self):
        return {
            'tg_name': self.tg_name,
            'positions': [p.to_dict() for p in self.positions]
        }

    def to_kdb(self):
        dt = Timer.datetime()
        return [p.to_kdb(dt) for p in self.positions]


class ActiveOrderInfo:

    # init from a dict (parsed from json)
    def __init__(self, d=None):
        d = d or {}
        self.exchange = ExchangeID.parse(d.get('exchange'))
        self.ticker = d.get('ticker')
        self.asset_type = AssetType.parse(d.get('asset_type'))
        self.order_id = d.get('order_id')
        self.order_ref = d.get('order_ref')
        self.price = d.get('price')
        self.volume = d.get('volume')
        self.volume_traded = d.get('volume_traded')
        self.direction = Direction.parse(d.get('direction'))
        self.offset_flag = OffsetFlag.parse(d.get('offset_flag'))
        self.order_status = OrderStatus.parse(d.get('order_status'))

    def __str__(self):
        return '<ord-{}-{} tkr={} px={} vol={} traded={} oid={} ref={} dir={} status={}>'.format(
            ExchangeID.read(self.exchange), AssetType.read(self.asset_type), self.ticker, self.price, self.volume,
            self.volume_traded, self.order_id, self.order_ref, Direction.read(self.direction), OrderStatus.read(self.order_status)
        )

    def to_influx(self, dt=None):
        if dt is None:
            dt = Timer.datetime()
        return {
            "measurement": None,
            "tags": {
                "exchange": ExchangeID.read(self.exchange),
                "ticker": self.ticker,
                "asset_type": AssetType.read(self.asset_type),
                "order_id": self.order_id,
                "order_ref": self.order_ref,
            },
            "time": dt,
            "fields": {
                "price": self.price,
                "volume": self.volume,
                "volume_traded": self.volume_traded,
                "direction": Direction.read(self.direction),
                "offset_flag": OffsetFlag.read(self.offset_flag),
                "order_status": OrderStatus.read(self.order_status),
            }
        }

    def to_dict(self):
        return {
            "exchange": ExchangeID.read(self.exchange),
            "ticker": self.ticker,
            "asset_type": AssetType.read(self.asset_type),
            "order_id": self.order_id,
            "order_ref": self.order_ref,
            "price": self.price,
            "volume": self.volume,
            "volume_traded": self.volume_traded,
            "direction": Direction.read(self.direction),
            "offset_flag": OffsetFlag.read(self.offset_flag),
            "order_status": OrderStatus.read(self.order_status),
        }


class RspActiveOrders:

    # init from a dict (parsed from json)
    def __init__(self, d=None):
        d = d or {}
        self.tg_name = d.get('tg_name')
        self.orders = [ActiveOrderInfo(item_d) for item_d in d.get('orders', [])]

    def size(self):
        return len(self.orders)

    def get(self, idx, default_value=None):
        if idx < self.size() and idx >= 0:
            return self.orders[idx]
        return default_value

    def __str__(self):
        s = '<orders tg={} count={}\n'.format(self.tg_name, len(self.orders))
        for order in self.orders:
            s += '\t' + str(order) + '\n'
        s += '>'
        return s

    @staticmethod
    def get_content_obj():
        return ActiveOrderInfo

    def to_influx(self):
        dt = Timer.datetime()
        return [info.to_influx(dt) for info in self.orders]

    def to_dict(self):
        return {
            'tg_name': self.tg_name,
            'orders': [order.to_dict() for order in self.orders]
        }


class RspHistoryTrades:

    def __init__(self, d=None):
        d = d or {}
        self.tg_name = d.get('tg_name')
        self.trades = [RtnTrade.from_dict(t) for t in d.get('trades', [])]

    def to_dict(self):
        return {
            'tg_name': self.tg_name,
            'trades': [
                t.to_dict() for t in self.trades
            ]
        }

    def __str__(self):
        s = '<trades tg={} count={}\n'.format(self.tg_name, len(self.trades))
        for trade in self.trades:
            s += '\t' + str(trade) + '\n'
        s += '>'
        return s


class ReqCancelActiveOrders(ReqBasic):
    _fields_ = [
        ('req_active_orders_id', ctypes.c_int64)
    ]

    def to_influx(self):
        return {
            "measurement": None,
            "tags": dict(ReqBasic.to_influx(self)['tags'], **{
                "req_active_orders_id": self.req_active_orders_id,
            }),
            "time": Timer.datetime(),
            "fields": ReqBasic.to_influx(self)['fields']
        }


class RspCancelActiveOrders(ctypes.Structure):
    _fields_ = [
        ('err_id', ctypes.c_int),
        ('err_msg', ctypes.c_char * MODULE_ERR_MSG_LENGTH),
    ]

    def __str__(self):
        return '<aoc eid={} err={}>'.format(self.err_id, self.err_msg)

    def to_influx(self):
        return {
            "measurement": None,
            "tags": {
                "err_id": self.err_id,
                "err_msg": self.err_msg
            },
            "time": Timer.datetime(),
            "fields": {
            }
        }

    def to_dict(self):
        return {
            'err_id': self.err_id,
            "err_msg": self.err_msg.decode(),
        }


class OrderBasicJ:

    def __init__(self, d=None):
        self.exchange = None if d is None else ExchangeID.parse(d['exchange'])
        self.ticker = None if d is None else d['ticker']
        self.source = None if d is None else d['source']
        self.price = None if d is None else d['price']
        self.volume = None if d is None else d['volume']
        self.order_type = None if d is None else d['order_type']
        self.direction = None if d is None else Direction.parse(d['direction'])
        self.offset_flag = None if d is None else OffsetFlag.parse(d['offset_flag'])

    def init(self, exchange, ticker, price, volume, direction, order_type, source='', offset_flag=OffsetFlag.NOT_AVAILABLE):
        self.exchange = exchange
        self.ticker = ticker
        self.source = source
        self.price = price
        self.volume = volume
        self.order_type = order_type
        self.direction = direction
        self.offset_flag = offset_flag

    def __str__(self):
        return '<ob ex={} ticker={} p={} v={} ot={} d={} of={}'.format(
            ExchangeID.read(self.exchange), self.ticker, self.price, self.volume,
            OrderType.read(self.order_type), Direction.read(self.direction), OffsetFlag.read(self.offset_flag)
        )

    def to_dict(self):
        return {
            'exchange': ExchangeID.read(self.exchange),
            'ticker': self.ticker,
            'source': self.source,
            'price': self.price,
            'volume': self.volume,
            'order_type': self.order_type,
            'direction': Direction.read(self.direction),
            'offset_flag': OffsetFlag.read(self.offset_flag)
        }


class BasketOrder:

    def __init__(self, d=None):
        self.basket_name = '' if d is None else d['basket_name']
        self.tg_name = '' if d is None else d['tg_name']
        self.order_id = -1 if d is None else d['order_id']
        self.client_name = '' if d is None else d['client_name']
        self.child_order_type = OrderType.NOT_AVAILABLE if d is None else d['child_order_type']
        self.algo_info = dict() if d is None else d['algo_info']
        self.orders = list() if d is None or d['orders'] is None else [OrderBasicJ(item_o) for item_o in d['orders']]

    def __str__(self):
        s = '<bo name={} tg={} id={} cli={}\n'.format(self.basket_name, self.tg_name, self.order_id, self.client_name)
        for od in self.orders:
            s += '\t' + str(od) + '\n'
        s += '>'
        return s

    def add_order(self, exchange, ticker, volume, direction, price=-1, order_type=OrderType.NOT_AVAILABLE,
                  source='', offset_flag=OffsetFlag.NOT_AVAILABLE):
        ''' warning! parent basket order's child_order_type take precedence over individual order's order_type '''
        assert order_type == OrderType.NOT_AVAILABLE or int(order_type / 10) == OrderType.PLAIN_ORDER_PREFIX

        od = OrderBasicJ()
        od.init(exchange, ticker, price, volume, direction, order_type, source, offset_flag)
        self.orders.append(od)

    def set_child_order_type(self, order_type):
        assert int(order_type / 10) != OrderType.BASKET_ORDER_PREFIX, "basket child order type cannot be of basket type"
        self.child_order_type = order_type

    def set_algo_info(self, **algo_args):
        self.algo_info = algo_args

    def to_dict(self):
        return {
            'basket_name': self.basket_name,
            'tg_name': self.tg_name,
            'order_id': self.order_id,
            'client_name': self.client_name,
            'child_order_type': self.child_order_type,
            'algo_info': self.algo_info,
            'orders': [od.to_dict() for od in self.orders]
        }
