vn.py量化社区
By Traders, For Traders.
Member
avatar
加入于:
帖子: 165
声望: 35

1.首先完善converter.py

class PositionHolding:
    """"""

    def __init__(self, contract: ContractData = None):
        """"""
        if contract:
            self.vt_symbol = contract.vt_symbol
            self.exchange = contract.exchange

        self.active_orders = {}
        self.order_id = ""
        self.long_pos = 0
        self.long_pnl = 0
        self.long_price = 0
        self.long_yd = 0
        self.long_td = 0
        self.short_pos = 0
        self.short_pnl = 0
        self.short_price = 0        
        self.short_yd = 0
        self.short_td = 0
        self.long_pos_frozen = 0
        self.long_yd_frozen = 0
        self.long_td_frozen = 0

        self.short_pos_frozen = 0
        self.short_yd_frozen = 0
        self.short_td_frozen = 0

    def update_position(self, position: PositionData):
        """"""
        if position.direction == Direction.LONG:
            self.long_pos = position.volume
            self.long_pnl = position.pnl
            self.long_yd = position.yd_volume
            self.long_td = self.long_pos - self.long_yd
            self.long_price = position.price
            self.long_pos_frozen = position.frozen
        else:
            self.short_pos = position.volume
            self.short_pnl = position.pnl            
            self.short_yd = position.yd_volume
            self.short_td = self.short_pos - self.short_yd
            self.short_price = position.price
            self.short_pos_frozen = position.frozen
    def update_order(self, order: OrderData):
        """"""
        #active_orders只记录未成交和部分成交委托单
        if order.status in [Status.NOTTRADED, Status.PARTTRADED]:
            self.active_orders[order.vt_orderid] = order
        else:
            if order.vt_orderid in self.active_orders:
                self.active_orders.pop(order.vt_orderid)

        self.calculate_frozen()

    def update_order_request(self, req: OrderRequest, vt_orderid: str):
        """"""
        #分离gateway_name和orderid
        gateway_name,*split_orderid = vt_orderid.split("_")
        if len(split_orderid) == 1:
            self.order_id = split_orderid[0]
        elif len(split_orderid) == 2:
            self.order_id = "_".join([split_orderid[0],split_orderid[1]])
        elif len(split_orderid) == 3:
            self.order_id = "_".join([split_orderid[0],split_orderid[1],split_orderid[2]])
        elif len(split_orderid) == 4:
            self.order_id = "_".join([split_orderid[0],split_orderid[1],split_orderid[2],split_orderid[3]])
        if self.order_id:
            order = req.create_order_data(self.order_id, gateway_name)
            self.update_order(order)

    def update_trade(self, trade: TradeData):
        """"""
        if trade.direction == Direction.LONG:
            if trade.offset == Offset.OPEN:
                self.long_td += trade.volume
            elif trade.offset == Offset.CLOSETODAY:
                self.short_td -= trade.volume
            elif trade.offset == Offset.CLOSEYESTERDAY:
                self.short_yd -= trade.volume
            elif trade.offset == Offset.CLOSE:
                if trade.exchange in [Exchange.SHFE, Exchange.INE]:
                    self.short_yd -= trade.volume
                else:
                    self.short_td -= trade.volume

                    if self.short_td < 0:
                        self.short_yd += self.short_td
                        self.short_td = 0
        else:
            if trade.offset == Offset.OPEN:
                self.short_td += trade.volume
            elif trade.offset == Offset.CLOSETODAY:
                self.long_td -= trade.volume
            elif trade.offset == Offset.CLOSEYESTERDAY:
                self.long_yd -= trade.volume
            elif trade.offset == Offset.CLOSE:
                if trade.exchange in [Exchange.SHFE, Exchange.INE]:
                    self.long_yd -= trade.volume
                else:
                    self.long_td -= trade.volume

                    if self.long_td < 0:
                        self.long_yd += self.long_td
                        self.long_td = 0

        self.long_pos = self.long_td + self.long_yd
        self.short_pos = self.short_td + self.short_yd

    def calculate_frozen(self):
        """"""
        self.long_pos_frozen = 0
        self.long_yd_frozen = 0
        self.long_td_frozen = 0

        self.short_pos_frozen = 0
        self.short_yd_frozen = 0
        self.short_td_frozen = 0

        for order in self.active_orders.values():
            # Ignore position open orders
            if order.offset == Offset.OPEN:
                continue

            frozen = order.volume - order.traded

            if order.direction == Direction.LONG:
                if order.offset == Offset.CLOSETODAY:
                    self.short_td_frozen += frozen
                elif order.offset == Offset.CLOSEYESTERDAY:
                    self.short_yd_frozen += frozen
                elif order.offset == Offset.CLOSE:
                    self.short_td_frozen += frozen

                    if self.short_td_frozen > self.short_td:
                        self.short_yd_frozen += (
                            self.short_td_frozen - self.short_td)
                        self.short_td_frozen = self.short_td
            elif order.direction == Direction.SHORT:
                if order.offset == Offset.CLOSETODAY:
                    self.long_td_frozen += frozen
                elif order.offset == Offset.CLOSEYESTERDAY:
                    self.long_yd_frozen += frozen
                elif order.offset == Offset.CLOSE:
                    self.long_td_frozen += frozen

                    if self.long_td_frozen > self.long_td:
                        self.long_yd_frozen += (
                            self.long_td_frozen - self.long_td)
                        self.long_td_frozen = self.long_td

            self.long_pos_frozen = self.long_td_frozen + self.long_yd_frozen
            self.short_pos_frozen = self.short_td_frozen + self.short_yd_frozen

    def convert_order_request_shfe(self, req: OrderRequest):
        """"""
        if req.offset == Offset.OPEN:
            return [req]

        if req.direction == Direction.LONG:
            pos_available = self.short_pos - self.short_pos_frozen
            td_available = self.short_td - self.short_td_frozen
        else:
            pos_available = self.long_pos - self.long_pos_frozen
            td_available = self.long_td - self.long_td_frozen

        if req.volume > pos_available:
            return []
        elif req.volume <= td_available:
            req_td = copy(req)
            req_td.offset = Offset.CLOSETODAY
            return [req_td]
        else:
            req_list = []

            if td_available > 0:
                req_td = copy(req)
                req_td.offset = Offset.CLOSETODAY
                req_td.volume = td_available
                req_list.append(req_td)

            req_yd = copy(req)
            req_yd.offset = Offset.CLOSEYESTERDAY
            req_yd.volume = req.volume - td_available
            req_list.append(req_yd)

            return req_list

    def convert_order_request_lock(self, req: OrderRequest):
        """"""
        if req.direction == Direction.LONG:
            td_volume = self.short_td
            yd_available = self.short_yd - self.short_yd_frozen
        else:
            td_volume = self.long_td
            yd_available = self.long_yd - self.long_yd_frozen

        # If there is td_volume, we can only lock position
        if td_volume:
            req_open = copy(req)
            req_open.offset = Offset.OPEN
            return [req_open]
        # If no td_volume, we close opposite yd position first
        # then open new position
        else:
            open_volume = max(0, req.volume - yd_available)
            req_list = []

            if yd_available:
                req_yd = copy(req)
                if self.exchange in [Exchange.SHFE, Exchange.INE]:
                    req_yd.offset = Offset.CLOSEYESTERDAY
                else:
                    req_yd.offset = Offset.CLOSE
                req_list.append(req_yd)

            if open_volume:
                req_open = copy(req)
                req_open.offset = Offset.OPEN
                req_open.volume = open_volume
                req_list.append(req_open)

            return req_list
Member
avatar
加入于:
帖子: 165
声望: 35

2.修改cta_strategy/engine

from collections import defaultdict,OrderedDict
    #--------------------------------------------------------------------------------------------------
    def get_position_detail(self, vt_symbol):
        """
        查询long_pos,short_pos(持仓),long_pnl,short_pnl(盈亏),active_order(未成交字典)
        收到PositionHolding类数据
        """
        try:
            return self.offset_converter.get_position_holding(vt_symbol)
        except:
            self.write_log(f"当前获取持仓信息为:{self.offset_converter.get_position_holding(vt_symbol)},等待获取持仓信息")
            position_detail = OrderedDict()     
            position_detail.active_orders = {} 
            position_detail.long_pos = 0
            position_detail.long_pnl = 0
            position_detail.long_yd = 0
            position_detail.long_td = 0
            position_detail.long_pos_frozen = 0
            position_detail.long_price = 0
            position_detail.short_pos = 0
            position_detail.short_pnl = 0          
            position_detail.short_yd = 0
            position_detail.short_td = 0
            position_detail.short_price = 0
            position_detail.short_pos_frozen = 0
            return position_detail

3.修改cta_strategy/template

    #--------------------------------------------------------------------------------------------------
    def get_position_detail(self, vt_symbol: str):
        """查询long_pos,short_pos(持仓),long_pnl,short_pnl(盈亏),active_order(未成交字典)"""
        return self.cta_engine.get_position_detail(vt_symbol)
Member
avatar
加入于:
帖子: 165
声望: 35

然后在策略里面调用get_position_detail函数就可以了,🎆🐔

Member
avatar
加入于:
帖子: 24
声望: 0

给月总点赞

Member
avatar
加入于:
帖子: 4
声望: 0

上弦之月 wrote:

然后在策略里面调用get_position_detail函数就可以了,🎆🐔
月总,请问这个函数在回测时有效吗?为什么我用于回测时返回错误AttributeError: 'BacktestingEngine' object has no attribute 'get_position_detail',求赐教!

Member
avatar
加入于:
帖子: 165
声望: 35

@很老的文 只能实盘用,回测参考这个帖子https://www.vnpy.com/forum/topic/1758-zi-yong-backtestingfen-xiang-guan-jian-ci-hui-ce-ying-yu-tong-ji-pyechartshua-tu-huan-you-empyricaltong-ji-zhi-biao

Member
avatar
加入于:
帖子: 29
声望: 0

这些函数是加在类里面,还是加在你说的文件后面就行了,单独的一个函数?

Member
avatar
加入于:
帖子: 6
声望: 0

如果要获取开仓均价,要怎么修改?

Member
avatar
加入于:
帖子: 4
声望: 1

caixiaoming wrote:

如果要获取开仓均价,要怎么修改?
兄弟你这个解决了吗?

Member
avatar
加入于:
帖子: 165
声望: 35

@caixiaoming self.get_position_detail(self.vt_symbol).long_price这样子

Member
avatar
加入于:
帖子: 6
声望: 0

上弦之月 wrote:

@caixiaoming self.get_position_detail(self.vt_symbol).long_price这样子

你好,感谢回复。
这个方法获取的价格是持仓均价,就是每天会随着结算价变动的价格。
上一贴子中是问开仓均价,买入的成本价,是不会变动的价格。
想问的就是有没有变法获得这个不会变动的价格。

Member
avatar
加入于:
帖子: 39
声望: 2

不错,受教了.

Member
avatar
加入于:
帖子: 8
声望: 0

感谢 月总!!太棒了!!

Member
avatar
加入于:
帖子: 48
声望: 0

最好能将这个函数封装到下一次正式版里面。

© 2015-2019 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号-3