예제 #1
0
 def __init__(self, name, events_pool, settings={}):
     super(SimpleBlotter, self).__init__(name)
     self.open_orders = set()
     self.positions = {}  # Contract: Position
     self.holding = {}  # 当前的资金 dict
     self.api = SimulateTraderAPI(self, events_pool)  # 模拟交易接口
     self._all_orders = []
     self._pre_settlement = 0     # 昨日结算价
     self._datetime = None  # 当前时间
     self._all_holdings = []   # 所有时间点上的资金 list of dict
     self._all_transactions = []
     self._capital = settings['capital']
예제 #2
0
class SimpleBlotter(Blotter):
    """
    简单的订单管理系统,直接给 :class:`quantdigger.engine.exchange.Exchange`
    对象发订单,没有风控。
    """
    def __init__(self, name, events_pool, settings={}):
        super(SimpleBlotter, self).__init__(name)
        self._open_orders = list()
        self._all_orders = []
        self._pre_settlement = 0  # 昨日结算价
        self._datetime = None  # 当前时间
        self.positions = {}  # Contract: Position
        self.holding = {}  # 当前的资金 dict
        self._all_holdings = []  # 所有时间点上的资金 list of dict
        self._all_transactions = []
        self.api = SimulateTraderAPI(self, events_pool)  # 模拟交易接口
        if settings:
            self._captial = settings['captial']  # 初始权益
        else:
            self._captial = 5000.0

    @property
    def all_holdings(self):
        """ 账号历史情况,最后一根k线处平所有仓位。"""
        if self.positions:
            self._force_close()
        return self._all_holdings

    @property
    def transactions(self):
        """ 成交明细,最后一根k线处平所有仓位。"""
        if self.positions:
            self._force_close()
        return self._all_transactions

    def _force_close(self):
        """ 在回测的最后一根k线以close价格强平持仓位。"""
        force_trans = []
        price_type = self._all_transactions[
            -1].price_type if self._all_transactions else PriceType.LMT
        for pos in self.positions.values():
            order = Order(self._datetime, pos.contract, price_type,
                          TradeSide.PING, pos.direction,
                          self._ticks[pos.contract], pos.quantity)
            force_trans.append(Transaction(order))
        for trans in force_trans:
            self._update_holding(trans)
            self._update_positions(trans)
        if force_trans:
            self.update_status(trans.datetime, False)
        self.positions = {}
        return

    def _init_state(self):
        self.holding = {
            'cash': self._captial,
            'commission': 0.0,
            'history_profit': 0.0,
            'position_profit': 0.0,
            'equity': self._captial
        }

    def update_data(self, ticks, bars):
        """ 当前价格数据更新。 """
        self._ticks = ticks
        self._bars = bars

    def update_datetime(self, dt):
        """
        在新的价格数据来的时候触发。
        """
        #
        if self._datetime == None:
            self._datetime = dt
            self._start_date = dt
            self._init_state()
        elif self._datetime.date() != dt.date():
            self._open_orders = []
        self._datetime = dt

    def update_status(self, dt, append=True):
        """ 更新历史持仓,当前权益。"""

        # 更新资金历史。
        dh = {}
        dh['datetime'] = dt
        dh['commission'] = self.holding['commission']
        profit = 0
        margin = 0
        order_margin = 0

        # 计算当前持仓历史盈亏。
        # 以close价格替代市场价格。
        is_stock = True  # 默认是股票回测
        for key, pos in self.positions.iteritems():
            new_price = self._ticks[key.contract]
            profit += pos.profit(new_price)
            ## @TODO 用昨日结算价计算保证金
            margin += pos.position_margin(new_price)
            if not key.contract.is_stock:
                is_stock = False  #

        # 计算限价报单的保证金占用
        for order in self._open_orders:
            assert (order.price_type == PriceType.LMT)
            new_price = self._ticks[order.contract]
            order_margin += order.order_margin(new_price)

        # 当前权益 = 初始资金 + 累积平仓盈亏 + 当前持仓盈亏 - 历史佣金总额
        dh['equity'] = self._captial + self.holding['history_profit'] + profit - \
                       self.holding['commission']
        dh['cash'] = dh['equity'] - margin - order_margin
        #print margin, dt
        if dh['cash'] < 0:
            if not is_stock:
                # 如果是期货需要追加保证金
                ## @bug 如果同时交易期货和股票,就有问题。
                raise Exception('需要追加保证金!')

        self.holding['cash'] = dh['cash']
        self.holding['equity'] = dh['equity']
        self.holding['position_profit'] = profit
        if append:
            self._all_holdings.append(dh)
        else:
            self._all_holdings[-1] = dh

    def update_signal(self, event):
        """
        处理策略函数产生的下单事件。
        """
        assert event.type == Event.SIGNAL
        valid_orders = []
        for order in event.orders:
            if self._valid_order(order):
                order.datetime = self._datetime
                self.api.order(order)
                valid_orders.append(order)
            else:
                continue
        self._open_orders.extend(valid_orders)
        self._all_orders.extend(valid_orders)
        #print "Receive %d signals!" % len(event.orders)
        #self.generate_naive_order(event.orders)

    def update_fill(self, event):
        """
        处理委托单成交事件。
        """
        assert event.type == Event.FILL
        t_order = None
        for i, order in enumerate(self._open_orders):
            if order.id == event.transaction.id:
                t_order = self._open_orders.pop(i)
                break
        assert (t_order)
        self._update_holding(event.transaction)
        self._update_positions(event.transaction)

    def _update_positions(self, trans):
        """ 更新持仓 """
        poskey = PositionKey(trans.contract, trans.direction)
        pos = self.positions.setdefault(poskey, Position(trans))
        #print len(self.positions)
        #print pos.contract, pos.quantity
        if trans.side == TradeSide.KAI:
            # 开仓
            pos.cost = (pos.cost * pos.quantity + trans.price *
                        trans.quantity) / (pos.quantity + trans.quantity)
            pos.quantity += trans.quantity
        elif trans.side == TradeSide.PING:
            # 平仓
            pos.quantity -= trans.quantity
            if pos.quantity == 0:
                del self.positions[poskey]

    def _update_holding(self, trans):
        """
        更新佣金和平仓盈亏。
        """
        # 每笔佣金,和数目无关!
        self.holding['commission'] += trans.commission
        # 平仓,更新历史持仓盈亏。
        if trans.side == TradeSide.PING:
            poskey = PositionKey(trans.contract, trans.direction)
            multi = 1 if trans.direction == Direction.LONG else -1
            profit = (trans.price -
                      self.positions[poskey].cost) * trans.quantity * multi
            self.holding['history_profit'] += profit
        self._all_transactions.append(trans)

    def _valid_order(self, order):
        if order.quantity <= 0:
            logger.warn("下单数量错误!")
            return False
        """ 判断订单是否合法。 """
        if order.side == TradeSide.PING:
            try:
                poskey = PositionKey(order.contract, order.direction)
                pos = self.positions[poskey]
                if pos.quantity >= order.quantity:
                    return True
            except KeyError:
                # 没有持有该合约
                logger.warn("不存在合约[%s]" % order.contract)
                #assert False
                return False
            logger.warn("下单仓位问题")
            return False
        elif order.side == TradeSide.KAI:
            if self.holding['cash'] < order.price * order.quantity:
                raise TradingError(err='没有足够的资金开仓')
            else:
                new_price = self._ticks[order.contract]
                self.holding['cash'] -= order.order_margin(new_price)
        return True
예제 #3
0
class SimpleBlotter(Blotter):
    """
    简单的订单管理系统,直接给 :class:`quantdigger.engine.exchange.Exchange`
    对象发订单,没有风控。
    """
    def __init__(self, name, events_pool, settings={}):
        super(SimpleBlotter, self).__init__(name)
        self.open_orders = set()
        self._all_orders = []
        self._pre_settlement = 0  # 昨日结算价
        self._datetime = None  # 当前时间
        self.positions = {}  # Contract: Position
        self.holding = {}  # 当前的资金 dict
        self._all_holdings = []  # 所有时间点上的资金 list of dict
        self._all_transactions = []
        self.api = SimulateTraderAPI(self, events_pool)  # 模拟交易接口
        if settings:
            self._capital = settings['capital']  # 初始权益
        else:
            self._capital = 5000.0

    @property
    def all_holdings(self):
        """ 账号历史情况,最后一根k线处平所有仓位。"""
        if self.positions:
            self._force_close()
        return self._all_holdings

    @property
    def transactions(self):
        """ 成交明细,最后一根k线处平所有仓位。"""
        if self.positions:
            self._force_close()
        return self._all_transactions

    def _force_close(self):
        """ 在回测的最后一根k线以close价格强平持仓位。 """
        force_trans = []
        price_type = self._all_transactions[
            -1].price_type if self._all_transactions else PriceType.LMT
        for pos in self.positions.values():
            order = Order(self._datetime, pos.contract, price_type,
                          TradeSide.PING, pos.direction,
                          self._ticks[pos.contract], pos.quantity)
            force_trans.append(Transaction(order))
        for trans in force_trans:
            self._update_holding(trans)
            self._update_positions(trans)
        if force_trans:
            self.update_status(trans.datetime, False)
        self.positions = {}
        return

    def _init_state(self):
        self.holding = {
            'cash': self._capital,
            'commission': 0.0,
            'history_profit': 0.0,
            'position_profit': 0.0,
            'equity': self._capital
        }

    def update_data(self, ticks, bars):
        """ 当前价格数据更新。 """
        self._ticks = ticks
        self._bars = bars

    def update_datetime(self, dt):
        """
        在新的价格数据来的时候触发。
        """
        #
        if self._datetime == None:
            self._datetime = dt
            self._start_date = dt
            self._init_state()
        elif self._datetime.date() != dt.date():
            for order in self.open_orders:
                if order.side == TradeSide.PING:
                    pos = self.positions[PositionKey(order.contract,
                                                     order.direction)]
                    pos.closable += order.quantity
            self.open_orders.clear()
            for key, pos in self.positions.iteritems():
                pos.closable += pos.today
                pos.today = 0
        self._datetime = dt

    def update_status(self, dt, append=True):
        """ 更新历史持仓,当前权益。"""
        # 更新资金历史。
        dh = {}
        dh['datetime'] = dt
        dh['commission'] = self.holding['commission']
        profit = 0
        margin = 0
        order_margin = 0
        # 计算当前持仓历史盈亏。
        # 以close价格替代市场价格。
        for key, pos in self.positions.iteritems():
            new_price = self._ticks[key.contract]
            profit += pos.profit(new_price)
            ## @TODO 用昨日结算价计算保证金
            margin += pos.position_margin(new_price)
        # 计算限价报单的保证金占用
        for order in self.open_orders:
            assert (order.price_type == PriceType.LMT)
            new_price = self._ticks[order.contract]
            order_margin += order.order_margin(new_price)

        # 当前权益 = 初始资金 + 累积平仓盈亏 + 当前持仓盈亏 - 历史佣金总额
        dh['equity'] = self._capital + self.holding['history_profit'] + profit - \
                       self.holding['commission']
        dh['cash'] = dh['equity'] - margin - order_margin
        if dh['cash'] < 0:
            for key in self.positions.iterkeys():
                if not key.contract.is_stock:
                    ## @NOTE  只要有一个是期货,在资金不足的时候就得追加保证金
                    raise Exception('需要追加保证金!')
        self.holding['cash'] = dh['cash']
        self.holding['equity'] = dh['equity']
        self.holding['position_profit'] = profit
        if append:
            self._all_holdings.append(dh)
        else:
            self._all_holdings[-1] = dh

    def update_signal(self, event):
        """
        处理策略函数产生的下单事件。
        """
        assert event.type == Event.SIGNAL
        new_orders = []
        for order in event.orders:
            if self._valid_order(order):
                order.datetime = self._datetime
                self.api.order(copy.deepcopy(order))
                new_orders.append(order)
            else:
                continue
        self.open_orders.update(new_orders)  # 改变对象的值,不改变对象地址。
        self._all_orders.extend(new_orders)
        for order in new_orders:
            if order.side == TradeSide.PING:
                pos = self.positions[PositionKey(order.contract,
                                                 order.direction)]
                pos.closable -= order.quantity
        #print "Receive %d signals!" % len(event.orders)
        #self.generate_naive_order(event.orders)

    def update_fill(self, event):
        """
        处理委托单成交事件。
        """
        ## @TODO 订单编号和成交编号区分开
        assert event.type == Event.FILL
        trans = event.transaction
        try:
            self.open_orders.remove(trans.order)
        except KeyError:
            if trans.order.side == TradeSide.CANCEL:
                raise TradingError(err='重复撤单')
            else:
                assert (False and '重复成交')
        self._update_holding(trans)
        self._update_positions(trans)

    def _update_positions(self, trans):
        """ 更新持仓 """
        poskey = PositionKey(trans.contract, trans.direction)
        if trans.side == TradeSide.CANCEL:
            pos = self.positions.get(poskey, None)
            if pos:
                pos.closable += trans.quantity
            return
        pos = self.positions.setdefault(poskey, Position(trans))
        if trans.side == TradeSide.KAI:
            pos.cost = (pos.cost * pos.quantity + trans.price *
                        trans.quantity) / (pos.quantity + trans.quantity)
            pos.quantity += trans.quantity
            if trans.contract.is_stock:
                pos.today += trans.quantity
            else:
                pos.closable += trans.quantity
            assert (pos.quantity == pos.today + pos.closable)
        elif trans.side == TradeSide.PING:
            pos.quantity -= trans.quantity
            if pos.quantity == 0:
                del self.positions[poskey]

    def _update_holding(self, trans):
        """
        更新佣金和平仓盈亏。
        """
        if trans.side == TradeSide.CANCEL:
            return
        # 每笔佣金,和数目无关!
        self.holding['commission'] += trans.commission
        # 平仓,更新历史持仓盈亏。
        if trans.side == TradeSide.PING:
            poskey = PositionKey(trans.contract, trans.direction)
            multi = 1 if trans.direction == Direction.LONG else -1
            profit = (trans.price -
                      self.positions[poskey].cost) * trans.quantity * multi
            #if self.name == 'A1': # 平仓调试
            #print "***********"
            #print self._datetime, profit
            self.holding['history_profit'] += profit
        self._all_transactions.append(trans)

    def _valid_order(self, order):
        """ 判断订单是否合法。 """
        if order.quantity <= 0:
            raise TradingError(err="交易数量不能小于0")
        # 撤单
        if order.side == TradeSide.CANCEL:
            if order not in self.open_orders:
                raise TradingError(err='撤销失败: 不存在该订单!')
        if order.side == TradeSide.PING:
            try:
                poskey = PositionKey(order.contract, order.direction)
                pos = self.positions[poskey]
                if pos.closable < order.quantity:
                    raise TradingError(err='可平仓位不足')
            except KeyError:
                # 没有持有该合约
                #logger.warn("不存在合约[%s]" % order.contract)
                raise TradingError(err="不存在合约[%s]" % order.contract)
        elif order.side == TradeSide.KAI:
            new_price = self._ticks[order.contract]
            if self.holding['cash'] < order.order_margin(new_price):
                raise TradingError(err='没有足够的资金开仓')
            else:
                self.holding['cash'] -= order.order_margin(new_price)
        return True
예제 #4
0
class SimpleBlotter(Blotter):
    """
    简单的订单管理系统,直接给 :class:`quantdigger.engine.exchange.Exchange`
    对象发订单,没有风控。
    """
    def __init__(self, name, events_pool, settings={}):
        super(SimpleBlotter, self).__init__(name)
        self.open_orders = set()
        self.positions = {}  # Contract: Position
        self.holding = {}  # 当前的资金 dict
        self.api = SimulateTraderAPI(self, events_pool)  # 模拟交易接口
        self._all_orders = []
        self._pre_settlement = 0     # 昨日结算价
        self._datetime = None  # 当前时间
        self._all_holdings = []   # 所有时间点上的资金 list of dict
        self._all_transactions = []
        self._capital = settings['capital']

    @property
    def all_holdings(self):
        """ 账号历史情况,最后一根k线处平所有仓位。"""
        if self.positions:
            # assert False
            self._force_close()
        return self._all_holdings

    @property
    def transactions(self):
        """ 成交明细,最后一根k线处平所有仓位。"""
        if self.positions:
            self._force_close()
        return self._all_transactions

    def update_data(self, ticks, bars):
        """ 当前价格数据更新。 """
        # self._ticks = ticks
        self._bars = bars

    def update_datetime(self, dt):
        """ 在新的价格数据来的时候触发。 """
        if self._datetime is None:
            self._datetime = dt
            self._start_date = dt
            self._init_state()
        elif self._datetime.date() != dt.date():
            for order in self.open_orders:
                if order.side == TradeSide.PING:
                    pos = self.positions[PositionKey(
                        order.contract, order.direction)]
                    pos.closable += order.quantity
            self.open_orders.clear()
            for key, pos in self.positions.iteritems():
                pos.closable += pos.today
                pos.today = 0
        self._datetime = dt

    def update_status(self, dt, at_baropen, append):
        """ 更新历史持仓,当前权益。"""
        # @TODO open_orders 和 postion_margin分开,valid_order调用前再统计?
        # 更新资金历史。
        dh = {}
        dh['datetime'] = dt
        dh['commission'] = self.holding['commission']
        pos_profit = 0
        margin = 0
        order_margin = 0
        # 计算当前持仓历史盈亏。
        # 以close价格替代市场价格。
        for key, pos in self.positions.iteritems():
            bar = self._bars[key.contract]
            new_price = bar.open if at_baropen else bar.close
            pos_profit += pos.profit(new_price)
            # @TODO 用昨日结算价计算保证金
            margin += pos.position_margin(new_price)
        # 计算未成交开仓报单的保证金占用
        for order in self.open_orders:
            assert(order.price_type == PriceType.LMT)
            bar = self._bars[order.contract]
            new_price = bar.open if at_baropen else bar.close
            if order.side == TradeSide.KAI:
                order_margin += order.order_margin(new_price)
        # 当前权益 = 初始资金 + 累积平仓盈亏 + 当前持仓盈亏 - 历史佣金总额
        dh['equity'] = self._capital + self.holding['history_profit'] + \
            pos_profit - self.holding['commission']
        # @TODO
        # 对于股票,Bar的开盘和收盘点资金验证是一致的。
        # 如果期货不一致,成交撮合时候也无法确定确切的时间点,
        # ,就无法确定精确的可用资金,可能因此导致cash<0, 就得加
        # 强平功能,使交易继续下去。
        dh['cash'] = dh['equity'] - margin - order_margin
        if dh['cash'] < 0:
            for key in self.positions.iterkeys():
                if not key.contract.is_stock:
                    # @NOTE  只要有一个是期货,在资金不足的时候就得追加保证金
                    raise Exception('需要追加保证金!')
        self.holding['cash'] = dh['cash']
        self.holding['equity'] = dh['equity']
        self.holding['position_profit'] = pos_profit
        if append:
            self._all_holdings.append(dh)
        else:
            self._all_holdings[-1] = dh

    def update_signal(self, event):
        """ 处理策略函数产生的下单事件。

        可能产生一系列order事件,在bar的开盘时间交易。
        """
        assert event.type == Event.SIGNAL
        new_orders = []
        for order in event.orders:
            errmsg = self._valid_order(order)
            if errmsg == '':
                order.datetime = self._datetime
                new_orders.append(order)
                if order.side == TradeSide.KAI:
                    self.holding['cash'] -= \
                        order.order_margin(self._bars[order.contract].open)
            else:
                logger.warn(errmsg)
                # print len(event.orders), len(new_orders)
                continue
        self.open_orders.update(new_orders)  # 改变对象的值,不改变对象地址。
        self._all_orders.extend(new_orders)
        for order in new_orders:
            self.api.order(copy.deepcopy(order))
        for order in new_orders:
            if order.side == TradeSide.PING:
                pos = self.positions[
                    PositionKey(order.contract, order.direction)]
                pos.closable -= order.quantity

    def update_fill(self, event):
        """ 处理委托单成交事件。 """
        # @TODO 订单编号和成交编号区分开
        assert event.type == Event.FILL
        trans = event.transaction
        try:
            self.open_orders.remove(trans.order)
        except KeyError:
            if trans.order.side == TradeSide.CANCEL:
                raise TradingError(err='重复撤单')
            else:
                assert(False and '重复成交')
        self._update_holding(trans)
        self._update_positions(trans)

    def _update_positions(self, trans):
        """ 更新持仓 """
        poskey = PositionKey(trans.contract, trans.direction)
        if trans.side == TradeSide.CANCEL:
            pos = self.positions.get(poskey, None)
            if pos:
                pos.closable += trans.quantity
            return
        pos = self.positions.setdefault(poskey, Position(trans))
        if trans.side == TradeSide.KAI:
            pos.cost = (pos.cost*pos.quantity + trans.price*trans.quantity) / \
                        (pos.quantity+trans.quantity)
            pos.quantity += trans.quantity
            if trans.contract.is_stock:
                pos.today += trans.quantity
            else:
                pos.closable += trans.quantity
            assert(pos.quantity == pos.today + pos.closable)
        elif trans.side == TradeSide.PING:
            pos.quantity -= trans.quantity
            if pos.quantity == 0:
                del self.positions[poskey]

    def _update_holding(self, trans):
        """ 更新佣金和平仓盈亏。 """
        if trans.side == TradeSide.CANCEL:
            return
        self.holding['commission'] += trans.commission
        # 平仓,更新历史持仓盈亏。
        if trans.side == TradeSide.PING:
            poskey = PositionKey(trans.contract, trans.direction)
            flag = 1 if trans.direction == Direction.LONG else -1
            profit = (trans.price-self.positions[poskey].cost) * \
                trans.quantity * flag * trans.volume_multiple
            self.holding['history_profit'] += profit
        self._all_transactions.append(trans)

    def _valid_order(self, order):
        """ 判断订单是否合法。 """
        if order.quantity <= 0:
            return "交易数量要大于0"
        # 撤单
        if order.side == TradeSide.CANCEL:
            if order not in self.open_orders:
                return '撤销失败: 不存在该订单!'
        if order.side == TradeSide.PING:
            try:
                poskey = PositionKey(order.contract, order.direction)
                pos = self.positions[poskey]
                if pos.closable < order.quantity:
                    return '可平仓位不足'
            except KeyError:
                # 没有持有该合约
                # logger.warn("不存在合约[%s]" % order.contract)
                return "不存在合约[%s]" % order.contract
        elif order.side == TradeSide.KAI:
            new_price = self._bars[order.contract].open
            if self.holding['cash'] < order.order_margin(new_price):
                # print self.holding['cash'], new_price * order.quantity
                return '没有足够的资金开仓'
        return ''

    def _force_close(self):
        """ 在回测的最后一根k线以close价格强平持仓位。 """
        force_trans = []
        if self._all_transactions:
            price_type = self._all_transactions[-1].price_type
        else:
            price_type = PriceType.LMT
        for pos in self.positions.values():
            order = Order(
                self._datetime,
                pos.contract,
                price_type,
                TradeSide.PING,
                pos.direction,
                self._bars[pos.contract].close,
                pos.quantity
            )
            force_trans.append(Transaction(order))
        for trans in force_trans:
            self._update_holding(trans)
            self._update_positions(trans)
        if force_trans:
            self.update_status(trans.datetime, False, False)
        self.positions = {}
        return

    def _init_state(self):
        self.holding = {
            'cash': self._capital,
            'commission':  0.0,
            'history_profit':  0.0,
            'position_profit': 0.0,
            'equity': self._capital
        }
예제 #5
0
class SimpleBlotter(Blotter):
    """
    简单的订单管理系统,直接给 :class:`quantdigger.engine.exchange.Exchange`
    对象发订单,没有风控。
    """
    def __init__(self, name, events_pool, settings={ }):
        super(SimpleBlotter, self).__init__(name)
        self.open_orders = set()
        self.positions = {}  # Contract: Position
        self.holding = {}  # 当前的资金 dict
        self.api = SimulateTraderAPI(self, events_pool) # 模拟交易接口
        self._all_orders = []
        self._pre_settlement = 0     # 昨日结算价
        self._datetime = None # 当前时间
        self._all_holdings = []   # 所有时间点上的资金 list of dict
        self._all_transactions = []
        self._capital = settings['capital']

    @property
    def all_holdings(self):
        """ 账号历史情况,最后一根k线处平所有仓位。""" 
        if self.positions:
            self._force_close() 
        return self._all_holdings

    @property
    def transactions(self):
        """ 成交明细,最后一根k线处平所有仓位。""" 
        if self.positions:
            self._force_close() 
        return self._all_transactions

    def update_data(self, ticks, bars):
        """ 当前价格数据更新。 """ 
        self._ticks = ticks
        self._bars = bars

    def update_datetime(self, dt):
        """ 在新的价格数据来的时候触发。 """
        if self._datetime == None:
            self._datetime = dt
            self._start_date = dt
            self._init_state()
        elif self._datetime.date() != dt.date():
            for order in self.open_orders:
                if order.side == TradeSide.PING:
                    pos = self.positions[PositionKey(order.contract, order.direction)]
                    pos.closable += order.quantity
            self.open_orders.clear()
            for key, pos in self.positions.iteritems():
                pos.closable += pos.today
                pos.today = 0
        self._datetime = dt

    def update_status(self, dt, append=True):
        """ 更新历史持仓,当前权益。"""
        # 更新资金历史。
        dh = { }
        dh['datetime'] = dt
        dh['commission'] = self.holding['commission']
        profit = 0
        margin = 0
        order_margin = 0;
        # 计算当前持仓历史盈亏。
        # 以close价格替代市场价格。
        for key, pos in self.positions.iteritems():
            new_price = self._ticks[key.contract]
            profit += pos.profit(new_price)
            ## @TODO 用昨日结算价计算保证金
            margin += pos.position_margin(new_price)
        # 计算限价报单的保证金占用
        for order in self.open_orders:
            assert(order.price_type == PriceType.LMT)
            new_price = self._ticks[order.contract]
            order_margin +=  order.order_margin(new_price)
        # 当前权益 = 初始资金 + 累积平仓盈亏 + 当前持仓盈亏 - 历史佣金总额 
        dh['equity'] = self._capital + self.holding['history_profit'] + profit - \
                       self.holding['commission'] 
        dh['cash'] = dh['equity'] - margin - order_margin
        if dh['cash'] < 0:
            for key in self.positions.iterkeys():
                if not key.contract.is_stock:
                    ## @NOTE  只要有一个是期货,在资金不足的时候就得追加保证金
                    raise Exception('需要追加保证金!')
        self.holding['cash'] = dh['cash']
        self.holding['equity'] = dh['equity']
        self.holding['position_profit'] = profit
        if append:
            self._all_holdings.append(dh)
        else:
            self._all_holdings[-1] = dh

    def update_signal(self, event):
        """ 处理策略函数产生的下单事件。 """
        assert event.type == Event.SIGNAL
        new_orders = []
        for order in event.orders:
            if self._valid_order(order):
                order.datetime = self._datetime
                self.api.order(copy.deepcopy(order))
                new_orders.append(order)
            else:
                continue
        self.open_orders.update(new_orders) # 改变对象的值,不改变对象地址。
        self._all_orders.extend(new_orders)
        for order in new_orders:
            if order.side == TradeSide.PING:
                pos = self.positions[PositionKey(order.contract, order.direction)]
                pos.closable -= order.quantity
        #print "Receive %d signals!" % len(event.orders)
        #self.generate_naive_order(event.orders)

    def update_fill(self, event):
        """ 处理委托单成交事件。 """
        ## @TODO 订单编号和成交编号区分开
        assert event.type == Event.FILL
        trans = event.transaction
        try:
            self.open_orders.remove(trans.order)
        except KeyError:
            if trans.order.side == TradeSide.CANCEL:
                raise TradingError(err='重复撤单') 
            else:
                assert(False and '重复成交')
        self._update_holding(trans)
        self._update_positions(trans)

    def _update_positions(self, trans):
        """ 更新持仓 """
        poskey = PositionKey(trans.contract, trans.direction)
        if trans.side == TradeSide.CANCEL:
            pos = self.positions.get(poskey, None)
            if pos:
                pos.closable += trans.quantity
            return
        pos = self.positions.setdefault(poskey, Position(trans))
        if trans.side == TradeSide.KAI:
            pos.cost = (pos.cost*pos.quantity + trans.price*trans.quantity) / \
                        (pos.quantity+trans.quantity)
            pos.quantity += trans.quantity
            if trans.contract.is_stock:
                pos.today += trans.quantity 
            else:
                pos.closable += trans.quantity
            assert(pos.quantity == pos.today + pos.closable)
        elif trans.side == TradeSide.PING:
            pos.quantity -= trans.quantity
            if pos.quantity == 0:
                del self.positions[poskey] 

    def _update_holding(self, trans):
        """ 更新佣金和平仓盈亏。 """
        if trans.side == TradeSide.CANCEL:
            return
        # 每笔佣金,和数目无关!
        self.holding['commission'] += trans.commission
        # 平仓,更新历史持仓盈亏。
        if trans.side == TradeSide.PING:
            poskey = PositionKey(trans.contract, trans.direction)
            flag = 1 if trans.direction == Direction.LONG else -1
            profit = (trans.price-self.positions[poskey].cost) * trans.quantity *\
                     flag * trans.volume_multiple
            #if self.name == 'A1': # 平仓调试
                #print "***********" 
                #print self._datetime, profit 
            self.holding['history_profit'] += profit
        self._all_transactions.append(trans)

    def _valid_order(self, order):
        """ 判断订单是否合法。 """ 
        if order.quantity<=0:
            raise TradingError(err="交易数量不能小于0")
        # 撤单
        if order.side == TradeSide.CANCEL:
            if order not in self.open_orders:
                raise TradingError(err='撤销失败: 不存在该订单!') 
        if order.side == TradeSide.PING:
            try:
                poskey = PositionKey(order.contract, order.direction)
                pos = self.positions[poskey]
                if pos.closable < order.quantity:
                    raise TradingError(err='可平仓位不足')
            except KeyError:
                # 没有持有该合约
                #logger.warn("不存在合约[%s]" % order.contract)
                raise TradingError(err="不存在合约[%s]" % order.contract)
        elif order.side == TradeSide.KAI:
            new_price = self._ticks[order.contract]
            if self.holding['cash'] < order.order_margin(new_price):
                raise TradingError(err='没有足够的资金开仓') 
            else:
                self.holding['cash'] -= order.order_margin(new_price)
        return True

    def _force_close(self):
        """ 在回测的最后一根k线以close价格强平持仓位。 """ 
        force_trans = []
        price_type = self._all_transactions[-1].price_type if self._all_transactions else PriceType.LMT 
        for pos in self.positions.values():
            order = Order(
                self._datetime,
                pos.contract,
                price_type,
                TradeSide.PING,
                pos.direction,
                self._ticks[pos.contract],
                pos.quantity
            )
            force_trans.append(Transaction(order))
        for trans in force_trans:
            self._update_holding(trans)
            self._update_positions(trans)
        if force_trans:
            self.update_status(trans.datetime, False)
        self.positions = { }
        return

    def _init_state(self):
        self.holding = {
            'cash': self._capital,
            'commission':  0.0,
            'history_profit':  0.0,
            'position_profit' : 0.0,
            'equity': self._capital
        }