首页 > 解决方案 > 将 R 转换为 Python 用于微观市场结构零智能算法,无法让市场事件的生成正常工作

问题描述

我有以下 R 代码,我想将其更改为 Python,但遇到了失误。运行代码时,似乎在发出取消买单或卖单时,它使用可用的买单数量或可用的卖单数量之一(nb,ns),因此当代码运行时,它会在多次生成后用完订单的事件。所以看来我试图实现的生成功能没有生成足够的订单。因此,订单减少的速度比增加的速度快。这就是为什么我的代码会出现 keyerror 的原因,因为它最终会出现在我的书中找不到的用于取消买单或卖单的 posns。下面是 R 代码,然后是 Python 代码。

R 代码。

#Book setup
L <- 30 #Set number of price levels to be included in iterations

# Generate initial book
LL <- 1000 #Total number of levels in buy and sell books

# Initialize book with asymptotic depth of 5 shares
initializeBook5 <- function()
{
  Price <<- -LL:LL    
  # Book shape is set to equal long-term average from simulation
  buySize <<- c(rep(5,LL-8),5,4,4,3,3,2,2,1,rep(0,LL+1))
  sellSize <<- c(rep(0,LL),0,1,2,2,3,3,4,4,5,rep(5,LL-8))
  book <<- data.frame(Price, buySize, sellSize ) 
  if(logging==T){eventLog <<- as.data.frame(matrix(0,nrow=numEvents,ncol=2))
  colnames(eventLog)<<-c("Type","Price")
  count <<- 0
  eventType <<- c("LB","LS","CB","CS","MB","MS")
  eventDescr <<- NA}
}


#Various utility functions
bestOffer <- function(){min(book$Price[book$sellSize>0])}
bestBid <- function(){max(book$Price[book$buySize>0])}
spread <- function(){bestOffer()-bestBid()}
mid <- function(){(bestOffer()+bestBid())/2}

#Functions to find mid-market
bidPosn<-function()length(book$buySize[book$Price<=bestBid()])
askPosn<-function()length(book$sellSize[book$Price<=bestOffer()])
midPosn<-function(){floor((bidPosn()+askPosn())/2)}

#Display center of book
go <- function(){book[(midPosn()-20):(midPosn()+20),]}

#Display book shape
bookShape<-function(band){c(book$buySize[midPosn()+(-band:0)],book$sellSize[midPosn()+1:band])}
bookPlot<-function(band){
  plot((-band:band),bookShape(band),
       col="red",type="l",xlab="Price",ylab="Quantity")
}

#Choose from L whole numbers in (1,...,L) with uniform probability
pick <- function(m){sample(1:m,1)}

# Switch logging on
logging <- T

#Buy limit order
limitBuyOrder <- function(price=NA){
  if (is.na(price))
  {prx <<- (bestOffer()-pick(L))}
  else prx <<-price  
  if(logging==T){eventLog[count,]<<- c("LB",prx)} 
  book$buySize[book$Price==prx]<<-book$buySize[book$Price==prx]+1} 

#Sell limit order
limitSellOrder <- function(price=NA){
  if (is.na(price))
  {prx <<- (bestBid()+pick(L))}
  else prx <<-price  
  if(logging==T){eventLog[count,] <<- c("LS",prx)}  
  book$sellSize[book$Price==prx]<<-book$sellSize[book$Price==prx]+1} 

#Cancel buy order            
cancelBuyOrder<-function(price=NA){
  q<-pick(nb) 
  tmp <- cumsum(rev(book$buySize))  #Cumulative buy size from 0
  posn <- length(tmp[tmp>=q]) #gives position in list where cumulative size >q
  prx <<- book$Price[posn] 
  if (!is.na(price)) {prx <<-price} 
  if(logging==T){eventLog[count,]<<- c("CB",prx)} 
  book$buySize[posn]<<-book$buySize[posn]-1}


#Cancel sell order
cancelSellOrder<-function(price=NA){
  q<-pick(ns) 
  tmp <- cumsum(book$sellSize)  #Cumulative sell size from 0
  posn <- length(tmp[tmp<q])+1 
  prx <<- book$Price[posn] 
  if (!is.na(price)) {prx <<-price}  
  if(logging==T){eventLog[count,]<<- c("CS",prx)} 
  book$sellSize[posn]<<-book$sellSize[posn]-1}

#Market buy order
marketBuyOrder <- function(){
  prx <<- bestOffer() 
  if(logging==T){eventLog[count,]<<- c("MB",prx)} 
  book$sellSize[book$Price==prx]<<-book$sellSize[book$Price==prx]-1}

#Market sell order
marketSellOrder <- function(){
  prx <<- bestBid() 
  if(logging==T){eventLog[count,]<<- c("MS",prx)} 
  book$buySize[book$Price==prx]<<-book$buySize[book$Price==prx]-1}


#Generate an event and update the buy and sell books
#Note that limit orders may be placed inside the spread
generateEvent <- function()
{
  nb <<- sum(book$buySize[book$Price>=(bestOffer()-L)]); # Number of cancelable buy orders
  ns <<- sum(book$sellSize[book$Price<=(bestBid()+L)]); # Number of cancelable sell orders
  eventRate <- nb*delta+ns*delta + mu +2*L*alpha;
  probEvent <- c(L*alpha,L*alpha,nb*delta,ns*delta,mu/2,mu/2)/eventRate;
  m <- sample(1:6, 1, replace = TRUE, probEvent); #Choose event type
  switch(m,
         limitBuyOrder(),
         limitSellOrder(),
         cancelBuyOrder(),
         cancelSellOrder(),
         marketBuyOrder(),
         marketSellOrder()
  );
  
}


logging <- F 

lambda <- 1
mus <- c(10,8,10,10)
nus <- c(1/5,1/5,1/6,1/8)
avgBookShapes<-as.data.frame(matrix(0,nrow=41,ncol=4))

for(i in 1:4){
    mu<-mus[i]
    nu<-nus[i]
    initializeBook5()

    numEvents <- 100000 # Average over 100,000 events
    avgBookShape <- bookShape(20)/numEvents
    for(count in 2:numEvents){
      generateEvent()
      avgBookShape <- avgBookShape+bookShape(20)/numEvents
    }

    avgBookShapes[,i]<-avgBookShape
}

Python代码

import numpy as np 
import matplotlib.pyplot as plt
import pandas as pd 
import random 
import math

class Zibook():
    def __init__(self,ll,l,alpha,mu,delta,num_events,logging=False):
        self.ll = ll #total number of levels in buy and sell
        self.l = l # set number of price levels to be included in iterations 
        self.alpha = alpha
        self.mu = mu 
        self.delta = delta
        self.num_events = num_events
        self.logging = logging
        price = np.array(list(range(-self.ll,self.ll +1,1)))
        buy_size = np.array([5]*(self.ll-8) + [5,4,4,3,3,2,2,1] + [0]*(self.ll+1))
        sell_size = np.array([0]*(self.ll) + [0,1,2,2,3,3,4,4,5] +[5]*(self.ll-8))
        book = pd.DataFrame(index=price,columns=['Price','Buy Size','Sell Size','Type'])
        book['Price'] = price
        book['Buy Size'] = buy_size
        book['Sell Size'] = sell_size
        book = book.reset_index(drop=True)
        self.book = book
        event_type = ['LB','LS','CB','CS','MB','MS']
        event_descr = np.nan
        x = list(range(0,self.num_events,1)) 
        event_log = pd.DataFrame(index=x,columns=['Type','Price'])
        self.event_log = event_log 
        nb = sum(self.book.loc[self.book.Price >= (self.best_offer()-self.l), 'Buy Size']) #number of cancellable  buy orders
        ns = sum(self.book.loc[self.book.Price <= (self.best_bid()+self.l), 'Sell Size']) #number of cancellable sell order
        self.nb = nb
        self.ns = ns

    def best_offer(self):
        df = self.book
        a = df.loc[df['Sell Size'] > 0,'Price'].min()
        return a

    def best_bid(self):
        df = self.book
        b =   df.loc[df['Buy Size']>0 ,'Price'].max()
        return b
    def spread(self):
        spread = (self.best_offer() - self.best_bid())/2
        return spread 

    def mid(self):
        mid = (self.best_offer() + self.best_bid())/2
        return mid 

    def bidposn(self):
        df = self.book
        a = len(df.loc[df.Price <= self.best_bid(),'Buy Size'])-1
        return a

    def askposn(self):
        df = self.book
        a = len(df[df['Price'] <= self.best_offer()]['Sell Size']) -1
        return a
    def midposn(self):
        df = self.book
        a = ((self.bidposn()+self.askposn())//2)
        return a
    
    def centerbook(self):
        df = self.book
        mid = self.midposn()
        return df[mid-20:mid +21]

    def bookshape(self,band):
        df = self.book
        mid = self.midposn()
        x = np.arange(-band,0)
        y = [df.loc[(mid+el),'Buy Size'] for el in x]
        x1 = np.arange(0,band+1 )
        z = [df.loc[(mid + el), 'Sell Size'] for el in x1]
        seq3 = np.concatenate((y,z),axis=0)
        return seq3

        
    def bookplot(self,band):
        x = list(range(-band,band+1,1))
        seq3 = self.bookshape(band)
        plt.plot(x,seq3, color='red')
        plt.xlabel('Price')
        plt.ylabel('Quantity')
        return plt.show()

    def pick(self,l):
        a= np.random.choice(l,1,replace=True,p=[1/l]*l)
        return a[0]

    def limitbuyorder(self,price=None):
        
        if price == None :
            price = (self.best_offer() - self.pick(self.l))
        else:
            price = price 
        df = self.book
        if self.logging == True:
            count = 0
            eventlog = self.event_log
            eventlog.loc[count,'Price'] = price
            eventlog.loc[count,'Type'] = 'LB'
        df.loc[df.Price==price,'Buy Size'] += 1
    def limitsellorder(self,price=None):
         
        if price == None :
            price = (self.best_bid() + self.pick(self.l))
        else:
            price = price 
        df = self.book
        if self.logging == True:
            count = 0
            eventlog = self.event_log
            eventlog.loc[count,'Price'] = price
            eventlog.loc[count,'Type'] = 'LS'
        df.loc[df.Price==price,'Sell Size'] += 1

    def cancelbuyorder(self,price=None):
        df = self.book
        if price == None:
            q = self.pick(self.nb)
            tmp = np.array(df['Buy Size'].to_list()[::-1]).cumsum()
            posn = len(tmp[tmp>=q]) - 1
        
            price = df.Price[posn]
            df.loc[posn,'Buy Size'] -= 1
        else:
            price = price 
            df.loc[df.Price==price,'Buy Size'] -= 1

        if self.logging == True:
            count = 0
            eventlog = self.event_log
            eventlog.loc[count,'Price'] = price
            eventlog.loc[count,'Type'] = 'CB'
        


    def cancelsellorder(self,price=None):
        #global ns
        df = self.book
        if price == None:
            q = self.pick(self.ns)
            tmp = np.array(df['Sell Size'].to_list()).cumsum()
            posn = len(tmp[tmp<q])
            price = df.Price[posn]
            df.loc[posn,'Sell Size'] -= 1
        else:
            price = price 
            df.loc[df.Price==price,'Sell Size'] -= 1
        if self.logging == True:
            count = 0
            eventlog = self.event_log
            eventlog.loc[count,'Price'] = price
            eventlog.loc[count,'Type'] = 'CS'
     

    def marketbuyorder(self,price=None):
        df = self.book
        price = self.best_offer()
        if self.logging == True:
            count = 0
            eventlog = self.event_log
            eventlog.loc[count,'Price'] = price
            eventlog.loc[count,'Type'] = 'MB'
        
        df.loc[df.Price==price,'Sell Size'] -= 1
     

    def marketsellorder(self,price=None):
        df = self.book
        price = self.best_bid()
        if self.logging == True:
            count = 0
            eventlog = self.event_log
            eventlog.loc[count,'Price'] = price
            eventlog.loc[count,'Type'] = 'MS'
        
        df.loc[df.Price==price,'Buy Size'] -= 1


    def generateevent(self):
        df = self.book
        nb = sum(df.loc[df.Price >= (self.best_offer()-self.l), 'Buy Size']) #number of cancellable  buy orders
        ns = sum(df.loc[df.Price <= (self.best_bid()+self.l), 'Sell Size']) #number of cancellable sell order
        eventRate = nb*self.delta +ns*self.delta + self.mu + 2*self.l*self.alpha 
        probEvent = (self.l*self.alpha + self.l*self.alpha + nb*self.delta + ns*self.delta + self.mu*0.5 + self.mu*0.5)/eventRate
        a = np.random.choice(6,1,replace=True,p=[probEvent/6]*6)
        idx = a[0]
        z= [self.limitbuyorder(),self.limitsellorder(),self.cancelbuyorder(),self.cancelsellorder(),self.marketbuyorder(),self.marketsellorder()]
        return z[idx]
    
   

alpha = 1
mu = 10
delta = 1/5
num_events = 100000

'''
a = Zibook(1000,30,alpha,mu,delta,num_events,logging=False)


a.limitbuyorder(price =a.best_bid())
a.limitbuyorder(price =a.best_bid())
a.bookplot(20)

#print(a.generateevent())
#print(a.cancelbuyorder(price=None))
'''
lalpha = [1,1,1,1]
lmu = [10,8,10,10]
ldelta = [1/5,1/5,1/6,1/8]
length = len(lalpha)

Avgbookshapes = np.array([])
num_events = 100000

for i in range(0,length,1):
    alpha = lalpha[i]
    mu = lmu[i]
    delta=ldelta[i]
    a = Zibook(1000,30,alpha,mu,delta,num_events,logging=False)
    for i1 in range(0,100,1):
        a.generateevent()
        #print(i1)

    avgbookshape = a.bookshape(20)/num_events
    #print(avgbookshape.shape)

    for i3 in range(2,num_events+1,1):
        a.generateevent()
        #print(i3)
        avgbookshape2 = a.bookshape(20)/num_events
        #print(avgbookshape2.shape)
        avgbookshape += avgbookshape2

    Avgbookshapes = np.append(Avgbookshapes,avgbookshape)

np.save('my_array',Avgbookshapes)

任何帮助将不胜感激(此算法的背景是它对微观市场结构的零智能模拟https://github.com/zecophy/MTH9879-Market-Microstructure-Models/blob/master/HW1/9879HW1_Chenyu_Zhao_graded.ipynb

标签: pythonrpandasnumpyquantitative-finance

解决方案


刚刚意识到我没有在 generateevent 函数中正确写出概率。但是代码仍然衰减到0个订单下面是python中的修改代码有人知道为什么订单会衰减而不是像R代码中那样增长吗?:

def generateevent(self):
        df = self.book
        nb = sum(df.loc[df.Price >= (self.best_offer()-self.l), 'Buy Size'])
        ns = sum(df.loc[df.Price <= (self.best_bid()+self.l), 'Sell Size']) #number of cancellable sell order
        eventRate = nb*self.delta +ns*self.delta + self.mu + 2*self.l*self.alpha 
        probEvent = np.array([self.l*self.alpha, self.l*self.alpha , nb*self.delta, ns*self.delta,self.mu*0.5,self.mu*0.5])/eventRate
        #print(probEvent)
        a = np.random.choice(6,1,replace=True,p=probEvent)
        idx = a[0]
        z= [self.limitbuyorder(),self.limitsellorder(),self.cancelbuyorder(),self.cancelsellorder(),self.marketbuyorder(),self.marketsellorder()]
        return z[idx]

推荐阅读