├── test.txt ├── README.md └── bayesian-market-maker.py /test.txt: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # machine-learning-market-maker 2 | Implementation of a Bayesian-style market maker in the vein of 'Intelligent Market-Making in Artificial Financial Markets' by Sanmay Das 3 | 4 | Member Variables: 5 | Symbol: Ticker for security 6 | Distribution: A map of prices with a probability for each price 7 | Pa: Ask price, double 8 | Pb: Bid price, double 9 | Alpha: Percentage of noisy informed traders, double 10 | Noise: Noise magnitude of noisy informed traders, double 11 | Shift: Difference from 0-profit market maker, double 12 | TruePrice: 'True price' traded upon by our model 13 | -------------------------------------------------------------------------------- /bayesian-market-maker.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import matplotlib.pyplot as plt 3 | import pandas.io.data as web 4 | import datetime 5 | 6 | from scipy.stats import norm 7 | 8 | class NaiveMarketMaker: 9 | 10 | def __init__(self, StockTicker, a, s): 11 | self.setSymbol = StockTicker 12 | self.setAlpha = a 13 | self.setNoise = s 14 | 15 | def getInitialPrice(self): 16 | # Check google finance and get current price 17 | # 18 | return(100) # placeholder value 19 | 20 | def getVolatility(self): 21 | # Check google finance and calculate volatility 22 | # 23 | return(.05) # placeholder value 24 | 25 | def initialize(self): 26 | # Fills out the base distribution using the normal CDF 27 | # For our purposes the tick size is $.01 28 | # 29 | # Inputs vol and V0 should be historical volatility and the current price 30 | 31 | self.Distribution = {} # Distribution is dictionary with {Price : Probability(Price)} 32 | self.TruePrice = [] 33 | 34 | self.V0 = self.getInitialPrice # Checks google finance and gets price 35 | self.vol = self.getVolatility # Calculates volatility from google finance 36 | 37 | Vmin = self.V0 - 4 * self.vol * self.V0 38 | Vmax = self.V0 + 4 * self.vol * self.V0 - .01 39 | 40 | V = 0 41 | i = 0 42 | while((Vmin + i) <= Vmax): 43 | V = Vmin + i 44 | self.Distribution[round(V, 2)] = norm.cdf(-4 * self.vol * self.V0 + i + .01, 0, self.vol * self.V0) - norm.cdf(-4 * self.vol * self.V0 + i, 0, self.vol * self.V0) 45 | 46 | i += .01 47 | 48 | self.Pb = self.V0 - self.vol * self.V0 * 0.5 49 | self.Pa = self.V0 + self.vol * self.V0 * 0.5 50 | 51 | self.TruePrice.append(self.V0) 52 | 53 | return(self.Pa, self.Pb) 54 | 55 | def updateDensity(self, OrderSide): 56 | # Updates the probability densities 57 | # 58 | # Getting BUY indicates that our ASK PRICE is hit (someone buys from us) 59 | # Getting SELL indicates that our BID PRICE is hit (someone sells to us) 60 | 61 | if OrderSide == "SELL": 62 | for price in self.Distribution: 63 | if price <= self.Pb: 64 | post = (1 - self.Alpha) * 0.5 + self.Alpha * norm.cdf(self.Pb - price, 0, self.Noise * self.V0) 65 | self.Distribution[price] = post * self.Distribution[price] / 0.5 66 | else: 67 | post = (1 - self.Alpha) * 0.5 + self.Alpha * (1 - norm.cdf(price - self.Pb, 0, self.Noise * self.V0)) 68 | self.Distribution[price] = post * self.Distribution[price] / 0.5 69 | else: 70 | for price in self.Distribution: 71 | if price <= self.Pa: 72 | post = (1 - self.Alpha) * 0.5 + self.Alpha * (1 - norm.cdf(self.Pa - price, 0, self.Noise * self.V0)) 73 | self.Distribution[price] = post * self.Distribution[price] / 0.5 74 | 75 | return 76 | 77 | def updateSpread(self): 78 | # Updates the bid-ask spread 79 | # 80 | # Add functionality to check the specific price we are hit at and to update that 81 | 82 | cumSum1 = 0 83 | cumSum2 = 0 84 | 85 | for price in self.Distribution: 86 | if price <= self.Pb: 87 | a = self.Pb - price 88 | cumSum1 += (0.5 - 0.5 * self.Alpha + self.Alpha * norm.cdf(a, 0, self.Noise * self.V0)) * self.Distribution[price] * price 89 | else: 90 | a = price - self.Pb 91 | cumSum2 += (0.5 - 0.5 * self.Alpha + self.Alpha * (1 - norm.cdf(a, 0, self.Noise * self.V0))) * self.Distribution[price] * price 92 | 93 | newPb = 2 * (cumSum1 + cumSum2) 94 | 95 | cumSum1 = 0 96 | cumSum2 = 0 97 | 98 | for price in self.Distribution: 99 | if price <= self.Pa: 100 | a = self.Pa - price 101 | cumSum1 += (0.5 - 0.5 * self.Alpha + self.Alpha * (1 - norm.cdf(a, 0, self.Noise * self.V0))) * self.Distribution[price] * price 102 | else: 103 | a = price - self.Pa 104 | cumSum2 += (0.5 - 0.5 * self.Alpha + self.Alpha * norm.cdf(a, 0, self.Noise * self.V0)) * self.Distribution[price] * price 105 | 106 | newPa = 2 * (cumSum1 + cumSum2) 107 | 108 | self.Pb = newPb 109 | self.Pa = newPa 110 | 111 | (self.TruePrice).append((self.Pa + self.Pb)/2) # Add the true price to our list 112 | return(self.Pa, self.Pb) # Returns Pa and Pb so that we can input the new orders 113 | 114 | def writeData(self): 115 | # Write vector to an array so we can graph it 116 | data = np.array(self.TruePrice) 117 | #plt.plot(data) 118 | #plt.show() 119 | return 120 | 121 | def run(self): 122 | # A loop that executes the strategy 123 | # 124 | # CONTAINED WITHIN API 125 | return 126 | 127 | def placeOrder(self): 128 | # Places an order on a security 129 | # 130 | # CONTAINED WITHIN API 131 | return 132 | 133 | def close(self): 134 | # Closes out of all positions 135 | # 136 | # CONTAINED WITHIN API 137 | return 138 | 139 | 140 | --------------------------------------------------------------------------------