先进先出匹配交易

2023-10-11  本文已影响0人  黄yy家的jby


class Item(object):
    """单笔交易对象,存储购买日期和数量 可能是买入也可能是卖出"""
    def __init__(self, time, num):

        if type(time) is int or type(time) is str:
            self.time = datetime.datetime.strptime(str(time),'%Y%m%d')
        else:
            self.time = time

        if type(num) is str:
            self.num = int(num)
        else:
            self.num = num


class Position(object):
    """头寸对象,存储某人员对于某股票的全部头寸 以队列模式先进先出"""
    def __init__(self, stock_name, person_name):
        self.items = []
        self.stock_name = stock_name
        self.person_name = person_name

    def is_empty(self):
        return self.items == []

    def buy(self, item):
        """有买入则在items列表里追加此次交易记录"""
        self.items.append(item)

    def sell(self, item, limit):
        """根据卖出的交易记录更新本头寸 返回可能存在的相关交易信息(以元组的列表返回)"""
        related = []
        # 首次记录先是卖的,则pass
        if len(self.items) == 0 :
            return related
        else:
            # 不断根据卖出数量抵消买入记录,时间最久远的先被抵消,完全抵消后离开队列,卖出数量抵完为止
            while item.num > 0:
                # 判断此次抵消的买入记录是否和卖出记录的日期差≤limit天
                if (item.time.date() - self.items[0].time.date()).days <= limit:
                    # 发现相关交易,将相关信息打包为元组,放入列表related
                    info = (self.person_name, self.stock_name, self.items[0].time,
                            self.items[0].num,
                            item.time,
                            min(item.num,self.items[0].num),
                            (item.time.date() - self.items[0].time.date()).days)
                    related.append(info)
                # 判断最远的一次买入是否能完全抵消剩余卖出数量(临界值稍微注意,和不能一样也需要删除队列头)
                if item.num >= self.items[0].num:
                    # 不能,则先用最远的买入抵消部分卖出,剩余的卖出数量继续被后面的买入抵消
                    item.num -= self.items[0].num
                    # 最远的买入记录离开队列,循环继续
                    del (self.items[0])
                    if len(self.items) == 0:  # 如果卖的比买的多,直接跳出循环
                        return related
                else:
                    # 能,则最远的买入记录完全消化剩余卖出数量,并留有余量,下一次循环会停止
                    self.items[0].num -= item.num
                    item.num = 0
            return related



def FIFO(df,col_people,col_stock,col_time,col_num,col_type,limit=1e4):
    df = df.sort_values(by=col_time)

    # dic 以人员,股票为索引存储所有头寸的字典
    dic = {}
    relate = []
    for row in df.iterrows():
        name = row[1][col_people]
        date = row[1][col_time]
        stock = row[1][col_stock]
        num = row[1][col_num]
        type = row[1][col_type]

        index = name + ','+stock
        if index not in dic:
            dic[index] = Position(person_name=name, stock_name=stock)

        if type == '买入':
            dic[index].buy(Item(date, num))

        else:
            #卖出交易返回信息
            relate += (dic[index].sell(Item(date,num),limit))
        print(name,date,stock,type)
    result = pd.DataFrame(relate)
    result.columns = ['PERSON','INSTRUMENT_CODE','BUY_TIME','BUY_VOLUME_CUMSUM','SELL_TIME','SELL_VOLUME','INTERVAL_DAYS']
    return result
上一篇 下一篇

猜你喜欢

热点阅读