SOR Model

Last updated: October 4th, 20192019-10-04Project preview
In [1]:
class SOR:
    def __init__(self, marketPlace, order, globalBook):
        self.marketPlace = marketPlace
        self.order = order
        self.stock = order.stock
        self.orderVolume = order.orderVolume
        self.orderPrice = order.orderPrice
        self.orderType = order.orderType
        self.possibleTrades = pd.DataFrame(columns = ["Price" ,"Volume" ,"Venue"])
        self.globalBook = globalBook
        self.tradeBook = globalBook[self.stock]
        self.priceLadders = {}
    
    #Retrieves the Price Ladders of the desired stock from each Venue
    # priceLadders is a dictionary {venue: priceLadder}
    def retrievePriceLadders(self):
        for venue, orderBooks in self.marketPlace.items():
            i = stocks.index(self.stock)
            orderBook = orderBooks[i]
            priceLadder = orderBook.getPriceLadder()
            self.priceLadders[venue] = priceLadder
        return self.priceLadders
    
    def displayPriceLadders(self):
        for venue in venues:
            i = venues.index(venue)
            priceLadder = SOR(market,order,book).retrievePriceLadders()[venues[i]]
            display(priceLadder)
    
    # Find the BUY orders of the stock which are priced equal to or over the orderPrice
    # Sort them by decreasing price, then decreasing volume
    def findBUYorders(self, venue, priceLadder):
        for i in range(0,20):
            if priceLadder["Price"].iloc[i] < self.orderPrice:
                break
            else:
                if priceLadder["BUY"].iloc[i] == 0:
                    pass
                else:
                    self.possibleTrades.loc[len(self.possibleTrades)] = [priceLadder["Price"].iloc[i], priceLadder["BUY"].iloc[i], venue]
        self.possibleTrades = self.possibleTrades.sort_values(["Price","Volume"], ascending = False)
        return self.possibleTrades
    
    # Find the SELL orders of the stock which are priced equal to or under the orderPrice
    # Sort them by increasing price, then decreasing volume 
    def findSELLorders(self, venue, priceLadder):
        for i in range(-20,0):
            i = -i
            if priceLadder["Price"].iloc[i] > self.orderPrice:
                break
            else:
                if priceLadder["SELL"].iloc[i] == 0:
                    pass
                else:
                    self.possibleTrades.loc[len(self.possibleTrades)] = [priceLadder["Price"].iloc[i], priceLadder["SELL"].iloc[i], venue]
        self.possibleTrades = self.possibleTrades.sort_values(["Price", "Volume"], ascending=[True, False])
        return self.possibleTrades
        
    # For each venue, if order is SELL, retrieve the BUY orders
    # and if order is BUY, retrieve the SELL orders
    def findPossibleTrades(self):
        for venue, priceLadder in self.priceLadders.items():
            if self.orderType == "SELL":
                self.findBUYorders(venue, priceLadder)
            if self.orderType == "BUY":
                self.findSELLorders(venue, priceLadder)
        self.possibleTrades = self.possibleTrades.reset_index(drop=True)
        return self.possibleTrades

    # If the order cannot be fulfilled, it is added to a venue at random
    def addUnfulfilledOrder(self):
        selectedVenue = random.choice(venues)
        for i in range(0,20):
            if self.priceLadders[selectedVenue]["Price"].iloc[i] == self.orderPrice:
                if self.orderType == "SELL":
                    self.priceLadders[selectedVenue].at[i,"SELL"] += self.orderVolume
                if self.orderType == "BUY":
                    self.priceLadders[selectedVenue].at[i,"BUY"] += self.orderVolume
    
    # Go through the possibleTrades and add those to be executed to executableTrades
    # Trades are picked first with best price, and then with largest volume
    # Cycle through best price with decreasnig volume, then move on to next best price
    def findExecutableTrades(self):
        neededVolume = self.orderVolume
        for i in self.possibleTrades.index:
            if self.possibleTrades["Volume"].iloc[i] >= neededVolume:
                self.possibleTrades.at[i,"Volume"] = neededVolume
                self.possibleTrades = self.possibleTrades[:(i+1)]
                break
            else:
                neededVolume -= self.possibleTrades["Volume"].iloc[i]
            self.possibleTrades.columns.name = "Trades"
            #self.executableTrades = self.possibleTrades
    
    # Update the stocks' TradeBook with Price, Volume, Venue, and Time of trade
    def updateBooks(self):
        for i in self.possibleTrades.index:
            price = self.possibleTrades["Price"].iloc[i]
            volume = self.possibleTrades["Volume"].iloc[i]
            venue = self.possibleTrades["Venue"].iloc[i]
            times = Time(len(self.tradeBook)).setTime()
            for j in range(0,20):
                if self.priceLadders[venue]["Price"].iloc[j] == price:
                    if self.orderType == "SELL":
                        self.priceLadders[venue].at[j,"BUY"] -= volume
                    if self.orderType == "BUY":
                        self.priceLadders[venue].at[j,"SELL"] -= volume
            self.tradeBook.loc[len(self.tradeBook)] = [self.orderType, price, volume, venue, times]
        return self.tradeBook
    
    # Run all methods to fully execute a trade
    def executeTrade(self):
        self.retrievePriceLadders()
        self.findPossibleTrades()
        if self.possibleTrades.empty == True:
            self.addUnfulfilledOrder()
        else:
            self.findExecutableTrades()
            self.updateBooks()
        return self.tradeBook
    
    def batchEexecuteTrades(self):
        for stock in stocks:
            print(stock.ticker)
            for i in range(20):
                order = Order(stock)
                SOR(market,order,book).executeTrade()
    
    # Returns globalTradeBook
    def getTradeBooks(self):
        return self.globalBook
Notebooks AI
Notebooks AI Profile20060