Welcome, guest | Sign In | My Account | Store | Cart

Simple approach to calculating FIFO pnl.

Python, 116 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from collections import deque

import random

'''
    Example below replicates 
    
    +75 MSFT 25.10
    +50 MSFT 25.12
    -100 MSFT 25.22
    
    Realized P&L = 75 * (25.22 - 25.10) + 25 * (25.22 - 25.12) = $ 11.50
    
    A Trade is split into a set of unit positions that are then dequeued on FIFO basis as part of Sell.

'''

number_of_sell_trades = 1000
max_sell_quentity = 5
min_sell_price = 23.00
max_sell_price = 27.00

class TradeManager():        

    def __init__(self):
        # FIFO queue that we can use to enqueue unit buys and
        # dequeue unit sells.
        self.fifo = deque()
        self.profit = []

    def __repr__(self):
        return 'position size: %d'%(len(self.fifo))
        
    def execute_with_total_pnl(self, direction, quantity, price):            
        #print direction, quantity, price, 'position size', len(self.fifo)
        
        if len(self.fifo) == 0:
            return 0
        
        if 'Sell' in (direction):            
            if len(self.fifo) >= quantity:                
                return sum([(price - fill.price) for fill in tm.execute(direction, quantity, price)])                
            else:
                return 0                
        else:
            return [tm.execute(direction, quantity, price)]           
            
    def execute(self, direction, quantity, price):        
        #print direction, quantity, price, 'position size', len(self.fifo)
        if direction in ('Buy'):            
            for i, fill in Trade(direction, quantity, price):                
                self.fifo.appendleft(fill)            
                yield fill
        elif direction in ('Sell'):
            for i, fill in Trade(direction, quantity, price):                
                yield self.fifo.pop()        

class Fill():    
        def __init__(self, price):
            self.price = price
            self.quantity = 1

class Trade():            
    def __init__(self, direction, quantity, price):
        self.direction = direction
        self.quantity = quantity
        self.price = price
        self.i = 0 
        
    def __iter__(self):
        return self
    
    def next(self):
        if self.i < self.quantity:
            i = self.i
            self.i += 1
            return i, Fill(self.price)
        else:
            raise StopIteration()
            
# create a TradeManager
tm = TradeManager()

# generate some buys
a = [i for i in tm.execute('Buy', 75, 25.10)]    
a = [i for i in tm.execute('Buy', 50, 25.12)]  

# generate sell
pnl = np.cumsum(tm.execute_with_total_pnl('Sell', 100, 25.22))

# how much did we make
print 'total pnl', pnl[-1:]

# try something more involved.
tm = TradeManager()
pnl_ending = []

# run n simulations 
for step in range(0,50):
    a = [i for i in tm.execute('Buy', 75000, 25)]    
    pnl = np.cumsum([tm.execute_with_total_pnl('Sell', quantity, random.uniform(min_sell_price, max_sell_price)) \
                 for quantity in [random.randint(0,max_sell_quentity) \
                                  for i in range(0,number_of_sell_trades,1)]])
    plot(pnl)
    pnl_ending.append(pnl[-1:][0])
    print 'step', step, 'pnl', pnl[-1:][0], 'avg. pnl', np.mean(pnl_ending), 'diff to mean', pnl[-1:][0]-np.mean(pnl_ending)
    
print 'avg, total pnl', np.mean(pnl_ending) #pnl[-1:][0]
show()

# bin the results
hist(pnl_ending, 25)
grid(True)
show()

# could lookat fitting and var.

Buy 75 25.1 position size 0 Buy 50 25.12 position size 75 Sell 100 25.22 position size 125 Sell 100 25.22 position size 125 total pnl [-11.5]