コード例 #1
0
ファイル: account.py プロジェクト: ssh352/ctpbee
    def __init__(self):
        self.position_manager = LocalPositionManager(app=None)
        # 每日资金情况
        self.daily_life = defaultdict(list)

        # 回测模式
        self.pattern = "t+0"

        # 起始资金 默认10w 以及冻结
        self.balance = 100000
        self.frozen = 0

        self.size = 5
        self.pricetick = 10

        self.daily_limit = 20

        # 手续费
        self.commission: float = 0

        # 滑点相关设置
        self.slip_page: float = 0

        # 当前日志信息
        self.date = None
コード例 #2
0
ファイル: account.py プロジェクト: stockServ/ctpbee
    def __init__(self, interface, name=None):
        """
        核心账户
        Args

        """
        self.account_id = name if name is not None else uuid.uuid4()
        # 成交接口
        self.interface = interface
        # 每日成交单信息
        self.daily_life = defaultdict(AliasDayResult)

        # 合约乘数
        self.size_map = {}
        # 每日下单限制
        self.daily_limit = 20
        self.pre_balance = 0
        # 账户当前的日期
        self.date = None
        self.count_statistics = 0
        # 初始资金
        self.initial_capital = 0
        # 账户权益
        # 保证金占用
        self.long_margin = 0
        self.short_margin = 0
        # 冻结的保证金
        self.long_frozen_margin = {}
        self.short_frozen_margin = {}
        # 冻结的手续费
        self.frozen_fee = {}
        # 多头净值
        self.long_balance = 0
        # 空头净值
        self.short_balance = 0
        self.frozen_premium = 0
        self.count = 0
        """ 
        fee应该是一个 {
            ag2012.SHFE: 200.1
        }
        """
        self.fee = {}
        self.init_position_manager_flag = False
        self.init = False
        self.position_manager = None
        self.margin_ratio = {}
        # commission_ratio 应该为{"ag2012.SHFE": {"close_today": 0.005, "close":0.005 }
        self.basic_info = None
        self.commission_ratio = defaultdict(dict)
        self.close_profit = {}
        self.turnover = 0
        self.pre_float = 0
        self.position_manager = LocalPositionManager(self)
        self.code_pnl = {}
コード例 #3
0
ファイル: record.py プロジェクト: sixuerain/ctpbee
 def __init__(self, app, event_engine):
     """"""
     self.bar = {}
     self.ticks = {}
     self.orders = {}
     self.trades = {}
     self.positions = {}
     self.accounts = {}
     self.contracts = {}
     self.logs = {}
     self.errors = {}
     self.shared = {}
     self.active_orders = {}
     self.event_engine = event_engine
     self.register_event()
     self.app = app
     self.position_manager = LocalPositionManager(app=self.app)
コード例 #4
0
ファイル: record.py プロジェクト: huangzhangfeng/ctpbee
 def __init__(self, app):
     """"""
     self.bar = {}
     self.ticks = {}
     self.orders = {}
     self.trades = {}
     self.positions = {}
     self.account = None
     self.contracts = {}
     self.logs = {}
     self.errors = []
     self.generators = {}
     self.active_orders = {}
     self.local_contract_price_mapping = {}
     self.app = app
     self.register_event()
     self.position_manager = LocalPositionManager(app=self.app)
     self.main_contract_mapping = defaultdict(list)
コード例 #5
0
ファイル: account.py プロジェクト: zhizunbao84/ctpbee
    def __init__(self, interface):
        self.interface = interface
        self.position_manager = LocalPositionManager(interface.params)
        # 每日资金情况
        self.daily_life = defaultdict(list)

        # 起始资金 默认10w 以及冻结
        self.balance = 100000
        self.frozen = 0

        self.size = 5
        self.pricetick = 10

        self.daily_limit = 20

        # 手续费
        self.commission: float = 0

        # 滑点相关设置
        self.slip_page: float = 0

        # 当前日志信息
        self.date = None
コード例 #6
0
 def update_params(self, params: dict):
     """ 更新本地账户回测参数 """
     for i, v in params.items():
         if i == "initial_capital" and not self.init:
             self.pre_balance = v
             self.initial_capital = v
             self.long_balance = v
             self.short_balance = v
             self.init = True
             continue
         else:
             pass
         setattr(self, i, v)
     if not self.init_position_manager_flag:
         self.position_manager = LocalPositionManager(self)
         self.init_position_manager_flag = True
     else:
         pass
コード例 #7
0
ファイル: account.py プロジェクト: altowu/ctpbee
    def __init__(self):
        self.positions = LocalPositionManager(app=None)
        # 每日资金情况
        self.daily_life = defaultdict(list)

        {
            "12-8": AliasDayResult(),
            "12-9": AliasDayResult(),
        }

        # 回测模式
        self.pattern = "t+0"

        # 起始资金 默认10w 以及冻结
        self.balance = 100000
        self.frozen = 0

        self.size = 5
        self.pricetick = 10

        self.daily_limit = 20

        # 手续费
        self.commission: float = 0

        # 滑点相关设置
        self.slip_page: float = 0

        self.slip_fixed: float = 0
        self.slip_open: bool = False
        self.slip_match: bool = True
        self.slip_limit: bool = True
        self.slip_out: bool = False
        self.cu = None
        # 账户持有持仓信息 ----->
        self.ServberPosition = defaultdict(defaultdict(PositionData))
コード例 #8
0
ファイル: record.py プロジェクト: huangzhangfeng/ctpbee
class AsyncRecorder(object):
    """
    data center
    """
    def __init__(self, app, event_engine):
        """"""
        self.main_contract_mapping = defaultdict(list)
        self.bar = {}
        self.ticks = {}
        self.orders = {}
        self.trades = {}
        self.positions = {}
        self.account = None
        self.contracts = {}
        self.logs = {}
        self.errors = []
        self.shared = {}
        self.generators = {}
        self.active_orders = {}
        self.event_engine = event_engine
        self.register_event()

        self.app = app
        self.position_manager = LocalPositionManager(app=self.app)

    @staticmethod
    def get_local_time():
        from datetime import datetime
        return datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    def register_event(self):
        """bind process function"""
        self.event_engine.register(EVENT_TICK, self.process_tick_event)
        self.event_engine.register(EVENT_ORDER, self.process_order_event)
        self.event_engine.register(EVENT_TRADE, self.process_trade_event)
        self.event_engine.register(EVENT_POSITION, self.process_position_event)
        self.event_engine.register(EVENT_ACCOUNT, self.process_account_event)
        self.event_engine.register(EVENT_CONTRACT, self.process_contract_event)
        self.event_engine.register(EVENT_BAR, self.process_bar_event)
        self.event_engine.register(EVENT_LOG, self.process_log_event)
        self.event_engine.register(EVENT_ERROR, self.process_error_event)
        self.event_engine.register(EVENT_SHARED, self.process_shared_event)
        self.event_engine.register(EVENT_LAST, self.process_last_event)
        self.event_engine.register(EVENT_INIT_FINISHED,
                                   self.process_init_event)
        self.event_engine.register(EVENT_TIMER, self.process_timer_event)

    async def process_timer_event(self):
        for x in self.app.extensions.values():
            await x()

    async def process_init_event(self, event):
        """ 处理初始化完成事件 """
        if event.data:
            self.app.init_finished = True
        for x in self.app.extensions.values():
            await x(deepcopy(event))

    async def process_last_event(self, event):
        """ 处理合约的最新行情数据 """
        data = event.data

        # 过滤掉数字 取中文做key
        key = "".join([x for x in data.symbol if not x.isdigit()])
        self.main_contract_mapping[key.upper()].append(data)

    @property
    def main_contract_list(self):
        """ 返回主力合约列表 """
        result = []
        for _ in self.main_contract_mapping.values():
            x = sorted(_, key=lambda x: x.open_interest, reverse=True)[0]
            result.append(x.local_symbol)
        return result

    def get_main_contract_by_code(self, code: str):
        """ 根据code取相应的主力合约 """
        d = self.main_contract_mapping.get(code.upper(), None)
        if not d:
            return None
        else:
            now = sorted(d, key=lambda x: x.open_interest, reverse=True)[0]
            pre = sorted(d, key=lambda x: x.pre_open_interest, reverse=True)[0]
            if pre.local_symbol == now.local_symbol:
                return pre
            else:
                return now

    @async_value_call
    async def process_shared_event(self, event):
        if self.shared.get(event.data.local_symbol, None) is not None:
            self.shared[event.data.local_symbol].append(event.data)
        else:
            self.shared[event.data.local_symbol] = []

    async def process_error_event(self, event: Event):
        self.errors.append({"time": self.get_local_time(), "data": event.data})
        self.app.logger.error(event.data)

    async def process_log_event(self, event: Event):
        self.logs[self.get_local_time()] = event.data
        if self.app.config.get("LOG_OUTPUT"):
            self.app.logger.info(event.data)

    @async_value_call
    async def process_bar_event(self, event: Event):
        bar = event.data
        local = self.bar.get(bar.local_symbol)
        if local is None:
            self.bar[bar.local_symbol] = {bar.interval: []}
        else:
            if self.bar[bar.local_symbol].get(bar.interval) is None:
                self.bar[bar.local_symbol] = {bar.interval: []}
        self.bar[bar.local_symbol][bar.interval].append(bar)

    @async_value_call
    async def process_tick_event(self, event: Event):
        """"""
        tick = event.data
        self.ticks[tick.local_symbol] = tick
        symbol = tick.symbol
        self.position_manager.update_tick(tick)
        # 生成datetime对象
        if not tick.datetime:
            if '.' in tick.time:
                tick.datetime = datetime.strptime(
                    ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f')
            else:
                tick.datetime = datetime.strptime(
                    ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S')
        bm = self.generators.get(symbol, None)
        if bm:
            bm.update_tick(tick)
        if not bm:
            self.generators[symbol] = generator(self.event_engine, self.app)

    @async_value_call
    async def process_order_event(self, event: Event):
        """"""

        order = event.data
        self.orders[order.local_order_id] = order
        # If order is active, then update data in dict.
        if order._is_active():
            self.active_orders[order.local_order_id] = order
        # Otherwise, pop inactive order from in dict
        elif order.local_order_id in self.active_orders:
            self.active_orders.pop(order.local_order_id)
        self.position_manager.update_order(order)

    @async_value_call
    async def process_trade_event(self, event: Event):
        """"""
        trade = event.data
        self.trades[trade.local_trade_id] = trade
        self.position_manager.update_trade(trade)

    @async_value_call
    async def process_position_event(self, event: Event):
        """"""
        position = event.data
        self.positions[position.local_position_id] = position
        self.position_manager.update_position(position)

    async def process_account_event(self, event: Event):
        """"""
        account = event.data
        self.account = account
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_contract_event(self, event: Event):
        """"""
        contract = event.data
        self.contracts[contract.local_symbol] = contract
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    def get_shared(self, symbol):
        return self.shared.get(symbol, None)

    def get_all_shared(self):
        return self.shared

    def get_bar(self, local_symbol):
        return self.bar.get(local_symbol, None)

    def get_all_bar(self):
        return self.bar

    def get_tick(self, local_symbol):
        return self.ticks.get(local_symbol, None)

    def get_order(self, local_order_id):
        return self.orders.get(local_order_id, None)

    def get_trade(self, local_trade_id):
        return self.trades.get(local_trade_id, None)

    def get_position(self, local_position_id):
        return self.positions.get(local_position_id, None)

    def get_account(self):
        return self.account

    def get_contract(self, local_symbol):
        return self.contracts.get(local_symbol, None)

    def get_all_ticks(self):
        """
        Get all tick data.
        """
        return list(self.ticks.values())

    def get_all_orders(self):
        """
        Get all order data.
        """
        return list(self.orders.values())

    def get_all_trades(self):
        """
        Get all trade data.
        """
        return list(self.trades.values())

    def get_all_positions(self):
        """
        Get all position data.
        """
        # return list(self.positions.values())
        return self.position_manager.get_all_positions()

    def get_errors(self):
        return self.errors

    def get_new_error(self):
        return self.errors[-1]

    def get_all_contracts(self):
        """
        Get all contract data.
        """
        return list(self.contracts.values())

    def get_all_active_orders(self, local_symbol: str = ""):
        if not local_symbol:
            return list(self.active_orders.values())
        else:
            active_orders = [
                order for order in self.active_orders.values()
                if order.local_symbol == local_symbol
            ]
            return active_orders
コード例 #9
0
ファイル: record.py プロジェクト: huangzhangfeng/ctpbee
class Recorder(object):
    """
    data center
    """
    def __init__(self, app):
        """"""
        self.bar = {}
        self.ticks = {}
        self.orders = {}
        self.trades = {}
        self.positions = {}
        self.account = None
        self.contracts = {}
        self.logs = {}
        self.errors = []
        self.generators = {}
        self.active_orders = {}
        self.local_contract_price_mapping = {}
        self.app = app
        self.register_event()
        self.position_manager = LocalPositionManager(app=self.app)
        self.main_contract_mapping = defaultdict(list)

    @staticmethod
    def get_local_time():
        from datetime import datetime
        return datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    def register_event(self):
        """ bind process function """

        function = lambda name: lambda event: getattr(
            self, f"process_{name}_event")(event)

        def connect(data):
            name = data[0]
            signal = data[1]
            temp_sig = getattr(signal, f"{name}_signal")
            temp_sig.connect(function(name=name), weak=False)
            return name

        def generate_params(data, signal):
            temp = []
            for x in data:
                temp.append((x, signal))
            return temp

        p = list(
            map(
                connect,
                generate_params(signal.common_signals.event,
                                signal.common_signals)))
        p = list(
            map(
                connect,
                generate_params(self.app.app_signal.event,
                                self.app.app_signal)))

    def process_timer_event(self, event):
        for x in self.app.extensions.values():
            x()

    def process_init_event(self, event):
        """ 处理初始化完成事件 """
        if event.data:
            self.app.init_finished = True
        for x in self.app.extensions.values():
            x(deepcopy(event))

    def process_last_event(self, event):
        """ 处理合约的最新行情数据 """
        data = event.data
        self.local_contract_price_mapping[data.local_symbol] = data.last_price
        # 过滤掉数字 取中文做key
        key = "".join([x for x in data.symbol if not x.isdigit()])
        self.main_contract_mapping[key.upper()].append(data)

    def process_error_event(self, event: Event):
        self.errors.append({"time": self.get_local_time(), "data": event.data})
        self.app.logger.error(event.data)

    def process_log_event(self, event: Event):
        self.logs[self.get_local_time()] = event.data
        if self.app.config.get("LOG_OUTPUT"):
            self.app.logger.info(event.data)

    @value_call
    def process_bar_event(self, event: Event):
        bar = event.data
        local = self.bar.get(bar.local_symbol)
        if local is None:
            self.bar[bar.local_symbol] = {bar.interval: []}
        else:
            if self.bar[bar.local_symbol].get(bar.interval) is None:
                self.bar[bar.local_symbol] = {bar.interval: []}
        self.bar[bar.local_symbol][bar.interval].append(bar)

    @value_call
    def process_tick_event(self, event: Event):
        """"""
        tick = event.data
        self.ticks[tick.local_symbol] = tick
        self.position_manager.update_tick(tick)
        # 生成datetime对象
        if not tick.datetime:
            if '.' in tick.time:
                tick.datetime = datetime.strptime(
                    ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f')
            else:
                tick.datetime = datetime.strptime(
                    ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S')
        bm = self.generators.get(tick.local_symbol, None)
        if bm:
            bm.update_tick(tick)
        if not bm:
            self.generators[tick.local_symbol] = generator(self.app)
            self.generators[tick.local_symbol].update_tick(tick)

    @value_call
    def process_order_event(self, event: Event):
        """"""
        order = event.data
        self.orders[order.local_order_id] = order
        # If order is active, then update data in dict.
        if order._is_active():
            self.active_orders[order.local_order_id] = order
        # Otherwise, pop inactive order from in dict
        elif order.local_order_id in self.active_orders:
            self.active_orders.pop(order.local_order_id)
        self.position_manager.update_order(order)

    @value_call
    def process_trade_event(self, event: Event):
        """"""
        trade = event.data
        self.trades[trade.local_trade_id] = trade

        self.position_manager.update_trade(trade)
        for value in self.app.extensions.values():
            if self.app.config['INSTRUMENT_INDEPEND']:
                if len(value.instrument_set) == 0:
                    warnings.warn(
                        "你当前开启策略对应订阅行情功能, 当前策略的订阅行情数量为0,请确保你的订阅变量是否为instrument_set,以及订阅具体代码"
                    )
                if event.data.local_symbol in value.instrument_set:
                    value(deepcopy(event))
            else:
                value(deepcopy(event))

    @value_call
    def process_position_event(self, event: Event):
        """"""
        position = event.data
        self.positions[position.local_position_id] = position
        self.position_manager.update_position(position)
        for value in self.app.extensions.values():
            if self.app.config['INSTRUMENT_INDEPEND']:
                if len(value.instrument_set) == 0:
                    warnings.warn(
                        "你当前开启策略对应订阅行情功能, 当前策略的订阅行情数量为0,请确保你的订阅变量是否为instrument_set,以及订阅具体代码"
                    )
                if event.data.local_symbol in value.instrument_set:
                    value(deepcopy(event))
            else:
                value(deepcopy(event))

    def process_account_event(self, event: Event):
        """"""
        account = event.data
        self.account = account

        for value in self.app.extensions.values():
            value(deepcopy(event))

    def process_contract_event(self, event: Event):
        """"""
        contract = event.data
        self.contracts[contract.local_symbol] = contract
        for value in self.app.extensions.values():
            value(deepcopy(event))

    def get_shared(self, symbol):
        return self.shared.get(symbol, None)

    def get_all_shared(self):
        return self.shared

    def get_bar(self, local_symbol):
        return self.bar.get(local_symbol, None)

    def get_all_bar(self):
        return self.bar

    def get_tick(self, local_symbol):
        return self.ticks.get(local_symbol, None)

    def get_order(self, local_order_id):
        return self.orders.get(local_order_id, None)

    def get_trade(self, local_trade_id):
        return self.trades.get(local_trade_id, None)

    def get_position(self, local_position_id):
        return self.positions.get(local_position_id, None)

    def get_account(self):
        return self.account

    def get_contract(self, local_symbol):
        return self.contracts.get(local_symbol, None)

    def get_all_ticks(self):
        """
        Get all tick data.
        """
        return list(self.ticks.values())

    def get_all_orders(self):
        """
        Get all order data.
        """
        return list(self.orders.values())

    def get_all_trades(self):
        """
        Get all trade data.
        """
        return list(self.trades.values())

    def get_all_positions(self):
        """
        Get all position data.
        """
        # return list(self.positions.values())
        return self.position_manager.get_all_positions()

    def get_errors(self):
        return self.errors

    def get_new_error(self):
        return self.errors[-1]

    def get_all_contracts(self):
        """
        Get all contract data.
        """
        return list(self.contracts.values())

    def get_all_active_orders(self, local_symbol: str = ""):
        if not local_symbol:
            return list(self.active_orders.values())
        else:
            active_orders = [
                order for order in self.active_orders.values()
                if order.local_symbol == local_symbol
            ]
            return active_orders

    @property
    def main_contract_list(self):
        """ 返回主力合约列表 """
        result = []
        for _ in self.main_contract_mapping.values():
            x = sorted(_, key=lambda x: x.open_interest, reverse=True)[0]
            result.append(x.local_symbol)
        return result

    def get_contract_last_price(self, local_symbol):
        """ 获取合约的最新价格 """
        return self.local_contract_price_mapping.get(local_symbol)

    def get_main_contract_by_code(self, code: str):
        """ 根据code取相应的主力合约 """
        d = self.main_contract_mapping.get(code.upper(), None)
        if not d:
            return None
        else:
            now = sorted(d, key=lambda x: x.open_interest, reverse=True)[0]
            pre = sorted(d, key=lambda x: x.pre_open_interest, reverse=True)[0]
            if pre.local_symbol == now.local_symbol:
                return pre
            else:
                return now

    def clear_all(self):
        """
        为了避免数据越来越大,需要清空数据
        :return:
        """
        self.ticks.clear()
        self.orders.clear()
        self.trades.clear()
        self.positions.clear()
        self.contracts.clear()
        self.errors.clear()
        self.shared.clear()
        self.generators.clear()
        self.active_orders.clear()
コード例 #10
0
ファイル: account.py プロジェクト: stockServ/ctpbee
class Account:
    """
    此账户可以作为一个基本的账户类进行使用, 但是不能作为完整一个App.
    需要配合 Interface 提供实时价格和收盘价格进行使用.

    详细参见函数API
    """

    def __init__(self, interface, name=None):
        """
        核心账户
        Args

        """
        self.account_id = name if name is not None else uuid.uuid4()
        # 成交接口
        self.interface = interface
        # 每日成交单信息
        self.daily_life = defaultdict(AliasDayResult)

        # 合约乘数
        self.size_map = {}
        # 每日下单限制
        self.daily_limit = 20
        self.pre_balance = 0
        # 账户当前的日期
        self.date = None
        self.count_statistics = 0
        # 初始资金
        self.initial_capital = 0
        # 账户权益
        # 保证金占用
        self.long_margin = 0
        self.short_margin = 0
        # 冻结的保证金
        self.long_frozen_margin = {}
        self.short_frozen_margin = {}
        # 冻结的手续费
        self.frozen_fee = {}
        # 多头净值
        self.long_balance = 0
        # 空头净值
        self.short_balance = 0
        self.frozen_premium = 0
        self.count = 0
        """ 
        fee应该是一个 {
            ag2012.SHFE: 200.1
        }
        """
        self.fee = {}
        self.init_position_manager_flag = False
        self.init = False
        self.position_manager = None
        self.margin_ratio = {}
        # commission_ratio 应该为{"ag2012.SHFE": {"close_today": 0.005, "close":0.005 }
        self.basic_info = None
        self.commission_ratio = defaultdict(dict)
        self.close_profit = {}
        self.turnover = 0
        self.pre_float = 0
        self.position_manager = LocalPositionManager(self)
        self.code_pnl = {}

    @property
    def margin(self):
        result = 0
        for x in self.position_manager.get_all_positions():
            result += x["price"] * x["volume"] * self.get_size_from_map(
                x["local_symbol"]) * self.get_margin_ration(
                x["local_symbol"])
        return result

    @property
    def frozen_margin(self):
        return sum(list(self.long_frozen_margin.values())) + sum(list(self.short_frozen_margin.values()))

    @property
    def to_object(self) -> AccountData:
        return AccountData._create_class(dict(accountid=self.account_id,
                                              local_account_id=f"{self.account_id}.SIM",
                                              frozen=self.frozen,
                                              balance=self.balance,
                                              ))

    @property
    def frozen(self):
        return sum(self.frozen_fee.values())

    @property
    def float_pnl(self):
        result = 0
        for pos in self.position_manager.get_all_positions():
            if pos['direction'] == "long":
                result += (self.interface.price_mapping[pos["local_symbol"]] - pos[
                    "price"]) * pos["volume"] * self.get_size_from_map(
                    pos["local_symbol"])
            else:
                result += (pos["price"] - self.interface.price_mapping[
                    pos["local_symbol"]]) * pos["volume"] * self.get_size_from_map(
                    pos["local_symbol"])
        return result

    def get_code_float_pnl(self):
        """ 获取每个品种当时的浮动盈亏 """
        result = {}
        for pos in self.position_manager.get_all_positions():
            if pos['direction'] == "long":
                pnl = (self.interface.price_mapping[pos["local_symbol"]] - pos[
                    "price"]) * pos["volume"] * self.get_size_from_map(
                    pos["local_symbol"])
            else:
                pnl = (pos["price"] - self.interface.price_mapping[
                    pos["local_symbol"]]) * pos["volume"] * self.get_size_from_map(
                    pos["local_symbol"])
            if result.get(pos["local_symbol"]) is None:
                result[pos["local_symbol"]] = pnl
            else:
                result[pos["local_symbol"]] += pnl
        return result

    def get_code_pnl(self):
        pnl = {}
        pnl.update(self.code_pnl)
        for code, profit in self.get_code_float_pnl().items():
            if code in pnl:
                pnl[code] += profit
            else:
                pnl[code] = profit
        return pnl

    @property
    def balance(self) -> float:
        return self.available + self.margin

    @property
    def available(self):
        """ 可用资金 = 前日权益 + 平仓盈亏 + 浮动盈亏  - 手续费  - 冻结手续费 - 保证金 """
        return self.pre_balance + sum(self.close_profit.values()) + self.float_pnl - sum(
            self.fee.values()) - self.frozen - self.margin - self.frozen_margin

    @property
    def logger(self):
        return self.interface.logger

    def get_margin_ration(self, local_symbol):
        """ 获取保证金比率"""
        if self.basic_info is not None:
            if "." in local_symbol:
                local_symbol = local_symbol.split(".")[0]
            lc = "".join(filter(str.isalpha, local_symbol))
            return self.basic_info[lc][self.interface.date].margin
        else:
            return self.margin_ratio.get(local_symbol)

    def get_commission(self, order: OrderData or TradeData, close_today=False):
        """ 获取手续费比率 """
        if self.basic_info is not None:
            if "." in order.local_symbol:
                local_symbol = order.local_symbol.split(".")[0]
            else:
                local_symbol = order.local_symbol
            lc = "".join(filter(str.isalpha, local_symbol))
            n = self.basic_info[lc][self.interface.date]  # """ 切换到下一个交易日 """
            if n.commission_type == 2:
                if close_today:
                    """ 平今 """
                    return n.close_today_ratio * order.price * order.volume * self.get_size_from_map(order.local_symbol)
                else:
                    return n.close_ratio * order.price * order.volume * self.get_size_from_map(order.local_symbol)
            else:
                if close_today:
                    return n.close_today_ratio * order.volume
                else:
                    return n.close_ratio * order.volume
        else:
            if close_today:
                return self.commission_ratio.get(order.local_symbol)[
                           "close_today"] * order.volume * order.price * self.get_size_from_map(order.local_symbol)
            else:
                return self.commission_ratio.get(order.local_symbol)[
                           "close"] * order.volume * order.price * self.get_size_from_map(order.local_symbol)

    def get_size_from_map(self, local_symbol):
        """ 获取合约乘数 """
        if self.basic_info is not None:
            if "." in local_symbol:
                local_symbol = local_symbol.split(".")[0]
            lc = "".join(filter(str.isalpha, local_symbol))
            return self.basic_info[lc][self.interface.date].size
        else:
            return self.size_map.get(local_symbol)

    def update_account_from_trade(self, data: TradeData or OrderData):
        """ 更新基础属性方法
        # 下单更新冻结的保证金
        # 成交更新持仓的保证金
        开仓手续费 /平仓手续费 平今手续费
        """
        if isinstance(data, TradeData):
            """ 成交属性 """
            if data.order_id in self.frozen_fee.keys():  # 如果已经成交那么清除手续费冻结..
                self.frozen_fee.pop(data.order_id)
            try:
                if data.offset == Offset.CLOSETODAY:
                    fee = self.get_commission(data, close_today=True)
                else:
                    fee = self.get_commission(data)
            except KeyError:
                raise ValueError("请在对应品种设置合理的手续费")
            if self.fee.get(data.local_symbol) is None:
                self.fee[data.local_symbol] = fee
            else:
                self.fee[data.local_symbol] += fee

            if data.offset == Offset.OPEN:
                """  开仓增加保证金 """
                self.count += data.volume
                if data.direction == Direction.LONG:
                    if data.order_id in self.long_frozen_margin.keys():  # 如果成交, 那么清除多头的保证金冻结
                        self.long_frozen_margin.pop(data.order_id)
                else:
                    if data.order_id in self.short_frozen_margin.keys():  # 如果成交, 那么清除空头的保证金冻结
                        self.short_frozen_margin.pop(data.order_id)
                self.turnover += data.volume * data.price
            else:
                if data.direction == Direction.LONG:
                    pos = self.position_manager.get_position_by_ld(data.local_symbol, Direction.SHORT)
                    try:
                        assert pos.volume >= data.volume
                    except Exception:
                        print(pos.volume, data.volume)
                        raise ValueError
                    close_profit = (pos.price - data.price) * data.volume * self.get_size_from_map(data.local_symbol)
                else:
                    pos = self.position_manager.get_position_by_ld(data.local_symbol, Direction.LONG)
                    assert pos.volume >= data.volume
                    close_profit = (data.price - pos.price) * data.volume * self.get_size_from_map(data.local_symbol)
                if self.close_profit.get(data.local_symbol) is None:
                    self.close_profit[data.local_symbol] = close_profit
                else:
                    self.close_profit[data.local_symbol] += close_profit
                if self.code_pnl.get(data.local_symbol) is None:
                    self.code_pnl[data.local_symbol] = close_profit
                else:
                    self.code_pnl[data.local_symbol] += close_profit

        else:
            raise TypeError("错误的数据类型,期望成交单数据 TradeData 而不是 {}".format(type(data)))

    def update_account_from_order(self, order: OrderData):
        """
        从order里面更新订单信息
        """
        if order.offset == Offset.CLOSETODAY:
            self.frozen_fee[order.order_id] = self.get_commission(order, close_today=True)
        else:
            self.frozen_fee[order.order_id] = self.get_commission(order)
        if order.offset == Offset.OPEN:
            """ 开仓增加保证金占用 """
            if order.direction == Direction.LONG:
                self.long_frozen_margin[order.order_id] = self.get_margin_ration(
                    order.local_symbol) * order.price * order.volume * self.get_size_from_map(order.local_symbol)
            else:
                self.short_frozen_margin[order.order_id] = self.get_margin_ration(
                    order.local_symbol) * order.price * order.volume * self.get_size_from_map(order.local_symbol)

        self.position_manager.update_order(order)

    def pop_order(self, order: OrderData):
        if order.direction == Direction.LONG:
            if order.order_id in self.long_frozen_margin:
                self.long_frozen_margin.pop(order.order_id)
        if order.direction == Direction.SHORT:
            if order.order_id in self.short_frozen_margin:
                self.short_frozen_margin.pop(order.order_id)
        if order.order_id in self.frozen_fee:
            self.frozen_fee.pop(order.order_id)

    def clear_frozen(self):
        """ 撤单的时候应该要清除所有的单子 并同时清除保证金占用和手续费冻结 """
        from ctpbee.constant import EVENT_ORDER, Status
        # for order in list(self.interface.pending.values()):
        #     """ 结算后需要把未所有的单子撤掉 """
        #     order.status = Status.CANCELLED
        #     order.time.hour = 15
        #     order.time.minute = 1
        #     self.interface.on_event(EVENT_ORDER, order)

        self.interface.pending.clear()
        self.frozen_fee.clear()
        self.long_frozen_margin.clear()
        self.short_frozen_margin.clear()
        self.position_manager.clear_frozen()

    def reset_attr(self):
        """ 重新设置属性 """
        self.frozen_premium = 0
        self.count = 0
        self.turnover = 0
        self.close_profit.clear()
        self.code_pnl.clear()
        self.interface.today_volume = 0
        for x in self.fee.keys():
            self.fee[x] = 0

    def close_position_by_amount(self, amount, price_mapping):
        """ 通过指定金额来金额来平仓直到available为正 """
        self.logger.info(f"{self.date} 正在按照指定金额进行平仓: {amount}")
        for position in self.position_manager.get_all_positions():
            margin = position["price"] * position["volume"] * self.get_size_from_map(
                position["local_symbol"]) * self.get_margin_ration(position["local_symbol"])
            if margin > amount:
                volume = amount / (position["price"] * self.get_size_from_map(
                    position["local_symbol"]) * self.get_margin_ration(position["local_symbol"]))
                if volume % 1 != 0:
                    volume = int(volume) + 1
                else:
                    volume = int(volume)
                amount = 0
            else:
                volume = position["volume"]
                amount -= margin

            if position["direction"] == "long":
                self.interface.action.cover(price_mapping[position["local_symbol"]], volume, position)
            else:
                self.interface.action.sell(price_mapping[position["local_symbol"]], volume, position)
            if amount <= 0:
                self.logger.info("已经发完足够包含指定保证金的平仓单")
                break
        if amount > 0:
            raise ValueError(f"你爆仓了!!!!, 什么策略????? 你的保证金: {self.margin} 可用:{self.available}")

    def is_traded(self, order: OrderData) -> bool:
        """ 当前账户是否足以支撑成交 """
        # 根据传入的单子判断当前的账户可用资金是否足以成交此单
        if order.offset != Offset.OPEN:
            """ 交易是否可平不足? """
            poss = self.position_manager.get_position(order.local_symbol)
            if not poss:
                return False, "此合约上无仓位"

            if order.direction == Direction.LONG:
                if order.volume > poss.short_pos:
                    """ 仓位不足 """
                    return False, f"平空头仓位不足 {order.local_symbol} volume: {order.volume}  持仓量: {poss.short_pos}"
                else:
                    return True, None
            else:
                if order.volume > poss.long_pos:
                    return False, f"平多头仓位不足 {order.local_symbol} volume: {order.volume}  持仓量: {poss.long_pos}"
                else:
                    return True, None
        order_amount = order.price * order.volume * self.get_size_from_map(
            order.local_symbol) * self.get_margin_ration(
            order.local_symbol)
        if self.available < order_amount or self.available < 0:
            """ 可用不足"""
            return False, f"资金可用不足, 当前可用: {self.available} 当前冻结保证金: {self.frozen_margin}"
        return True, None

    def update_trade(self, trade: TradeData) -> None:
        """
        当前选择调用这个接口的时候就已经确保了这个单子是可以成交的,
        make sure it can be traded if you choose to call this method,
        :param trade:交易单子/trade
        :return:
        """
        self.update_account_from_trade(trade)
        self.position_manager.update_trade(trade=trade)
        tr = ""
        assert trade.volume > 0
        for pos in self.position_manager.get_all_positions():
            if pos["direction"] == "long":
                tr += f"{pos['local_symbol']}  long :{pos['volume']} \n"
            else:
                tr += f"{pos['local_symbol']}  short :{pos['volume']} \n"
        if isinstance(trade.time, datetime):
            self.interface.position_detail[trade.time.strftime("%Y-%m-%d %H:%M:%S")] = tr
        elif isinstance(trade.time, str):
            self.interface.position_detail[trade.time] = tr

    def settle(self, interface_date=None):
        """ 生成今天的交易数据, 同时更新前日数据 ,然后进行持仓结算 """
        if not self.date:
            date = interface_date
        else:
            date = self.date
        """ 结算撤掉所有单 归还冻结 """
        self.clear_frozen()
        if self.available < 0:
            self.logger.info("你的可用不足, 进行减仓")
            self.close_position_by_amount(abs(self.available), self.interface.price_mapping)

        p = AliasDayResult(
            **{"balance": self.balance,
               "margin": self.margin,
               "available": self.available,
               "short_balance": self.short_balance,
               "long_balance": self.long_balance,
               "date": date,
               "commission": sum([x for x in self.fee.values()]),
               "net_pnl": self.balance - self.pre_balance,
               "count": self.count,
               "turnover": self.turnover
               })
        code_pnl = self.get_code_pnl()
        self.interface.on_event(EVENT_WARNING,
                                "Settlement:  " + str(
                                    date) + f" net: {round(self.balance, 2)}"
                                + f" margin: {round(self.margin, 2)}"
                                  f" net_pnl: {self.balance - self.pre_balance} "
                                  f" close_profit: {round(sum(self.close_profit.values()), 2)}"
                                  f" float_pnl: {round(self.float_pnl, 2)}"
                                  f" code_pnl: {code_pnl}"
                                  f" fee:{round(sum(self.fee.values()), 2)} ")
        self.pre_float = self.float_pnl
        self.daily_life[date] = deepcopy(p._to_dict())
        self.pre_balance = self.balance
        self.long_balance = self.balance
        self.short_balance = self.balance
        self.reset_attr()
        self.position_manager.covert_to_yesterday_holding(**self.interface.price_mapping)
        # 归还所有的冻结
        self.date = interface_date

    def via_aisle(self):
        self.position_manager.update_size_map(self.interface.params)
        if self.interface.date != self.date:
            self.date = self.interface.date
        else:
            pass

    def update_params(self, params: dict):
        """ 更新本地账户回测参数 """
        for i, v in params.items():
            if i == "initial_capital" and not self.init:
                self.pre_balance = v
                self.initial_capital = v
                self.long_balance = v
                self.short_balance = v
                self.init = True
                continue
            else:
                pass
            setattr(self, i, v)

    @property
    def result(self):
        # 根据daily_life里面的数据 获取最后的结果
        result = defaultdict(list)
        for daily in self.daily_life.values():
            for key, value in daily.items():
                result[key].append(value)
        try:
            df = DataFrame.from_dict(result).set_index("date")
        except KeyError:
            print("-------------------------------------------------")
            print("|          好像没有结算数据哦!                    |")
            print("-------------------------------------------------")
            return {}
        try:
            import matplotlib.pyplot as plt
            df['balance'].plot()
            plt.show()
        except ImportError as e:
            pass
        finally:
            return self._cal_result(df)

    def get_mapping(self, d):
        mapping = {}
        for i, v in self.daily_life.items():
            mapping[str(i)] = v.get(d)
        return mapping

    def _cal_result(self, df: DataFrame) -> dict:
        result = dict()
        df["return"] = (df["balance"] / df["balance"].shift(1) - 1).fillna(0)
        df["high_level"] = (
            df["balance"].rolling(
                min_periods=1, window=len(df), center=False).max()
        )
        df["draw_down"] = df["balance"] - df["high_level"]
        df["dd_percent"] = df["draw_down"] / df["high_level"] * 100
        result['initial_capital / 初始资金'] = self.initial_capital
        result['start_date / 起始日期'] = df.index[0]
        result['end_date / 结束日期'] = df.index[-1]
        result['total_days / 交易天数'] = len(df)
        result['profit_days / 盈利天数'] = len(df[df["net_pnl"] > 0])
        result['loss_days / 亏损天数'] = len(df[df["net_pnl"] < 0])
        result['end_balance / 结束资金'] = round(df["balance"].iloc[-1], 2)
        result['max_draw_down / 最大回撤'] = round(df["draw_down"].min(), 2)
        result['max_dd_percent / 最大回撤百分比'] = str(round(df["dd_percent"].min(), 2)) + "%"
        result['total_pnl / 总盈亏'] = round(df["net_pnl"].sum(), 2)
        result['daily_pnl / 平均日盈亏'] = round(result['total_pnl / 总盈亏'] / result['total_days / 交易天数'], 2)
        result['total_commission / 总手续费'] = round(df["commission"].sum(), 2)
        result['daily_commission / 日均手续费'] = round(result['total_commission / 总手续费'] / result['total_days / 交易天数'], 2)
        result['total_turnover / 开仓总资金'] = round(df["turnover"].sum(), 2)
        result['daily_turnover / 每日平均开仓资金'] = round(result['total_turnover / 开仓总资金'] / result['total_days / 交易天数'], 2)
        result['total_count / 总成交次数'] = df["count"].sum()
        result['daily_count / 日均成交次数'] = round(result['total_count / 总成交次数'] / result['total_days / 交易天数'], 2)
        result['total_return / 总收益率'] = str(
            round((result['end_balance / 结束资金'] / self.initial_capital - 1) * 100, 2)) + "%"

        by_year_return_std = df["return"].std() * np.sqrt(245)
        df["return_x"] = df["return"] + 1
        try:
            profit_ratio = geometric_mean(df["return_x"].to_numpy()) ** 245 - 1
        except ValueError:
            print("boom 计算几何平均数存在负数, 本次回测作废")
            return {}
        result['annual_return / 年化收益率'] = str(round(profit_ratio * 100, 2)) + "%"
        result['return_std / 年化标准差'] = str(round(by_year_return_std * 100, 2)) + "%"
        result['volatility / 波动率'] = str(round(df["return"].std() * 100, 2)) + "%"
        if by_year_return_std != 0:
            result['sharpe / 年化夏普率'] = (profit_ratio - 2.5 / 100) / by_year_return_std
        else:
            result['sharpe / 年化夏普率'] = "计算出错"
        return result
コード例 #11
0
 def __init__(self, interface):
     self.interface = interface
     self.position_manager = LocalPositionManager(interface.params)
     # 每日资金情况
     self.daily_life = defaultdict(AliasDayResult)
     self.date = None
コード例 #12
0
class Account:
    """
    账户类

    支持成交之后修改资金 , 对外提供API

    """
    balance = 100000
    frozen = 0
    size = 5
    pricetick = 10
    daily_limit = 20
    commission: float = 0

    def __init__(self, interface):
        self.interface = interface
        self.position_manager = LocalPositionManager(interface.params)
        # 每日资金情况
        self.daily_life = defaultdict(AliasDayResult)
        self.date = None

    def is_traded(self, trade: TradeData) -> bool:
        """ 当前账户是否足以支撑成交 """
        # 根据传入的单子判断当前的账户资金和冻结 是否足以成交此单
        if trade.price * trade.volume < self.balance - self.frozen:
            """ 可用不足"""
            return False
        return True

    def update_trade(self, trade: TradeData) -> None:
        """
        当前选择调用这个接口的时候就已经确保了这个单子是可以成交的,

        make sure it can be traded if you choose to call this method,

        :param trade:交易单子/trade_id
        :return:
        """
        # 根据单子 更新当前的持仓 ----->
        if not self.date:
            self.date = self.interface.date
        if self.interface.date != self.date:
            """ 新的一天 """
            p = AliasDayResult(
                **{
                    "balance": self.balance,
                    "frozen": self.frozen,
                    "available": self.balance - self.frozen
                })
            self.daily_life[self.date] = p
            self.date = self.interface.date
        if self.commission != 0:
            commission_expense = trade.price * trade.volume
        else:
            commission_expense = 0
        self.balance -= commission_expense
        # todo : 更新本地账户数据, 如果是隔天数据, 那么统计战绩 -----> AliasDayResult,然后推送到字典 。 以日期为key
        self.position_manager.update_trade(trade=trade)

    @property
    def result(self):
        # 计算并获取最后的结果
        df = DataFrame.from_dict(self.daily_life).set_index("datetime")
        return df
コード例 #13
0
class AsyncRecorder(object):
    """
    data center
    """

    def __init__(self, app, event_engine):
        """"""
        self.bar = {}
        self.ticks = {}
        self.orders = {}
        self.trades = {}
        self.positions = {}
        self.accounts = {}
        self.contracts = {}
        self.logs = {}
        self.errors = []
        self.shared = {}
        self.generators = {}
        self.active_orders = {}
        self.event_engine = event_engine
        self.register_event()

        self.app = app
        self.position_manager = LocalPositionManager(app=self.app)

    @staticmethod
    def get_local_time():
        from datetime import datetime
        return datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    def register_event(self):
        """bind process function"""
        self.event_engine.register(EVENT_TICK, self.process_tick_event)
        self.event_engine.register(EVENT_ORDER, self.process_order_event)
        self.event_engine.register(EVENT_TRADE, self.process_trade_event)
        self.event_engine.register(EVENT_POSITION, self.process_position_event)
        self.event_engine.register(EVENT_ACCOUNT, self.process_account_event)
        self.event_engine.register(EVENT_CONTRACT, self.process_contract_event)
        self.event_engine.register(EVENT_BAR, self.process_bar_event)
        self.event_engine.register(EVENT_LOG, self.process_log_event)
        self.event_engine.register(EVENT_ERROR, self.process_error_event)
        self.event_engine.register(EVENT_SHARED, self.process_shared_event)

    async def process_shared_event(self, event):
        if self.shared.get(event.data.local_symbol, None) is not None:
            self.shared[event.data.local_symbol].append(event.data)
        else:
            self.shared[event.data.local_symbol] = []
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_error_event(self, event: Event):
        self.errors.append({"time": self.get_local_time(), "data": event.data})
        print(self.get_local_time() + ": ", event.data)

    async def process_log_event(self, event: Event):
        self.logs[self.get_local_time()] = event.data
        if self.app.config.get("LOG_OUTPUT"):
            print(self.get_local_time() + ": ", event.data)
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_bar_event(self, event: Event):
        bar = event.data
        local = self.bar.get(bar.local_symbol)
        if local is None:
            self.bar[bar.local_symbol] = {bar.interval: []}
        else:
            if self.bar[bar.local_symbol].get(bar.interval) is None:
                self.bar[bar.local_symbol] = {bar.interval: []}
        self.bar[bar.local_symbol][bar.interval].append(bar)

        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_tick_event(self, event: Event):
        """"""
        tick = event.data
        self.ticks[tick.local_symbol] = tick
        symbol = tick.symbol
        self.position_manager.update_tick(tick)
        # 生成datetime对象
        if not tick.datetime:
            if '.' in tick.time:
                tick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f')
            else:
                tick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S')
        bm = self.generators.get(symbol, None)
        if bm:
            bm.update_tick(tick)
        if not bm:
            self.generators[symbol] = generator(self.event_engine)

        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_order_event(self, event: Event):
        """"""

        order = event.data
        self.orders[order.local_order_id] = order
        # If order is active, then update data in dict.
        if order._is_active():
            self.active_orders[order.local_order_id] = order
        # Otherwise, pop inactive order from in dict
        elif order.local_order_id in self.active_orders:
            self.active_orders.pop(order.local_order_id)
        self.position_manager.update_order(order)
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_trade_event(self, event: Event):
        """"""
        trade = event.data
        self.trades[trade.local_trade_id] = trade

        self.position_manager.update_trade(trade)
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_position_event(self, event: Event):
        """"""
        position = event.data
        self.positions[position.local_position_id] = position
        self.position_manager.update_position(position)
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_account_event(self, event: Event):
        """"""
        account = event.data
        self.accounts[account.local_account_id] = account
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    async def process_contract_event(self, event: Event):
        """"""
        contract = event.data
        self.contracts[contract.local_symbol] = contract
        for value in self.app.extensions.values():
            await value(deepcopy(event))

    def get_shared(self, symbol):
        return self.shared.get(symbol, None)

    def get_all_shared(self):
        return self.shared

    def get_bar(self, local_symbol):
        return self.bar.get(local_symbol, None)

    def get_all_bar(self):
        return self.bar

    def get_tick(self, local_symbol):
        return self.ticks.get(local_symbol, None)

    def get_order(self, local_order_id):
        return self.orders.get(local_order_id, None)

    def get_trade(self, local_trade_id):
        return self.trades.get(local_trade_id, None)

    def get_position(self, local_position_id):
        return self.positions.get(local_position_id, None)

    def get_account(self, local_account_id):
        return self.accounts.get(local_account_id, None)

    def get_contract(self, local_symbol):
        return self.contracts.get(local_symbol, None)

    def get_all_ticks(self):
        """
        Get all tick data.
        """
        return list(self.ticks.values())

    def get_all_orders(self):
        """
        Get all order data.
        """
        return list(self.orders.values())

    def get_all_trades(self):
        """
        Get all trade data.
        """
        return list(self.trades.values())

    def get_all_positions(self):
        """
        Get all position data.
        """
        return self.position_manager.get_all_positions()

    def get_errors(self):
        return self.errors

    def get_new_error(self):
        return self.errors[-1]

    def get_all_accounts(self):
        """
        Get all account data.
        """
        return list(self.accounts.values())

    def get_all_contracts(self):
        """
        Get all contract data.
        """
        return list(self.contracts.values())

    def get_all_active_orders(self, local_symbol: str = ""):
        if not local_symbol:
            return list(self.active_orders.values())
        else:
            active_orders = [
                order
                for order in self.active_orders.values()
                if order.local_symbol == local_symbol
            ]
            return active_orders
コード例 #14
0
ファイル: account.py プロジェクト: ssh352/ctpbee
class Account:
    """
    账户类

    支持成交之后修改资金 , 对外提供API

    """

    def __init__(self):
        self.position_manager = LocalPositionManager(app=None)
        # 每日资金情况
        self.daily_life = defaultdict(list)

        # 回测模式
        self.pattern = "t+0"

        # 起始资金 默认10w 以及冻结
        self.balance = 100000
        self.frozen = 0

        self.size = 5
        self.pricetick = 10

        self.daily_limit = 20

        # 手续费
        self.commission: float = 0

        # 滑点相关设置
        self.slip_page: float = 0

        # 当前日志信息
        self.date = None

    def is_traded(self, trade: TradeData) -> bool:
        """ 当前账户是否足以支撑成交 """
        # 根据传入的单子判断当前的账户资金和冻结 是否足以成交此单
        if trade.price * trade.volume < self.balance - self.frozen:
            """ 可用不足"""
            return False
        return True

    def update_trade(self, trade: TradeData) -> None:
        """
        当前选择调用这个接口的时候就已经确保了这个单子是可以成交的,

        make sure it can be traded if you choose to call this method,

        :param trade:交易单子/trade_id
        :return:
        """
        # 根据单子 更新当前的持仓和----->

        if trade.datetime.date != self.date:
            """ 新的一天 """
            p = AliasDayResult({"balance": self.balance, "frozen": self.frozen, "avaiable": self.balance - self.frozen})
            self.daily_life[self.date] = p
            self.date = trade.datetime.date

        commission_expense = trade.price * trade.volume
        self.balance -= commission_expense
        # todo : 更新本地账户数据, 如果是隔天数据, 那么统计战绩, -----> AliasDayResult,然后推送到字典 。 以日期为key

        self.position_manager.update_trade(trade=trade)

    @property
    def result(self):
        # 计算并获取最后的结果
        df = DataFrame.from_dict(self.daily_life).set_index("datetime")
        return df