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]

 Created by alexander baker on Tue, 10 Feb 2015 (MIT)