Guest User

Untitled

a guest
Feb 25th, 2018
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.98 KB | None | 0 0
  1. from functools import partial
  2. import wst.core.gromit as gromit
  3. from wst.ui.application import SimpleApp, SimpleAppView, SimpleAppController
  4. from wst.ui.controls import Button, Label, TextField, IFrame
  5. from wst.ui.layout import Col, Row, VList
  6. import datetime
  7. from wst.ts.tsfns import ts_object
  8. from wst.lib.tenor import ContractTenor
  9. from wst.core.analytics import bs
  10. import scipy.stats
  11. import numpy
  12. import math
  13. from mpl_toolkits.mplot3d import axes3d
  14. import matplotlib.pyplot as plt
  15. from matplotlib import cm
  16. # Shit Code, BSM returns zero. Shall check later
  17.  
  18. # We follow the MVC pattern to define a complete application in python. The platform has a special
  19. # dependency graph framework that we use to make applications reactive without too much code. If
  20. # you run this app and see what it does first, then look at how its constructed. You should be able
  21. # to get a reasonably functional web app without writing and javascript/css/html, however if you
  22. # web dev skills you can certainly make the app nicer if you like.
  23.  
  24. volatilities = []
  25. prices = []
  26.  
  27. def show_view(model, name):
  28. model.target_url.set_value(name)
  29.  
  30. class ViewModel(gromit.Object):
  31. @gromit.fn(gromit.CanSet)
  32. def target_url(self):
  33. return "./#/stock"
  34.  
  35. class Model(gromit.Object):
  36. '''Model class for the calculator.
  37.  
  38. Implement the model (back end) of the application. The model has two inputs fields with a
  39. special decorator and and output field which the same decorator with different settings.
  40.  
  41. You can see from playing with the app that when you type into the inputs the Sum function
  42. runs and the new value gets pushed into the view. This is magically happening in part due
  43. to the decorators below. Understanding these graph is an advanced topic, for now its
  44. sufficient to note that something interesting is happening which can be used to create
  45. reactive behavior, but there are some caveats.
  46. '''
  47.  
  48. @gromit.fn(gromit.Stored)
  49. def Input1(self):
  50. return 'Energy/CMECLopts'
  51.  
  52. def getVolitility(self,call,strike_price,price,exp,today):
  53.  
  54. print(call)
  55. print(strike_price)
  56. print(price)
  57.  
  58. is_call = call
  59.  
  60. spot = int(price * 100)
  61. strike = int(strike_price * 100)
  62. # exp_date = datetime.date(2018, 7, 31)
  63. today = datetime.date(2018, 2, 20)
  64. texp = texp = (exp - today).days / 365.
  65.  
  66. print(spot)
  67. print(strike)
  68.  
  69. try:
  70. vol = bs.imp_vol(
  71. is_call,
  72. spot,
  73. strike,
  74. texp,
  75. 0,
  76. 0,
  77. 697
  78. )
  79. except:
  80. return False
  81.  
  82. print('Volatility:', vol)
  83. return vol
  84.  
  85. def checkCallPrice(self,price, mean, std, strike_price, exp):
  86. today = datetime.date(2018, 2, 20)
  87. dtm = (exp - today).days / 365.
  88. d = (numpy.log(price / strike_price) + ((0.03 + std/2) * dtm)) / (std*numpy.sqrt(dtm))
  89. d_two = (numpy.log(price / strike_price) + ((0.03 - std/2) * dtm)) / (std*numpy.sqrt(dtm))
  90. bsm = price * (scipy.stats.norm(mean, std).pdf(d)) - (price * math.exp(-0.03*dtm) * scipy.stats.norm(mean,std).pdf(d_two))
  91. print(bsm)
  92.  
  93. def checkPutPrice(self, price, mean, std, strike_price, exp):
  94. today = datetime.date(2018, 2, 20)
  95. dtm = (exp - today).days / 365.
  96. d = (numpy.log(price / strike_price) + ((0.03 + std/2) * dtm)) / (std*numpy.sqrt(dtm))
  97. d_two = (numpy.log(price / strike_price) + ((0.03 - std/2) * dtm)) / (std*numpy.sqrt(dtm))
  98. bsm = (price * math.exp(-0.03*dtm)* scipy.stats.norm(mean,std).pdf(d_two * -1)) - price * (scipy.stats.norm(mean, std).pdf(d * -1))
  99. print(bsm)
  100.  
  101. def calcStockStuff(self):
  102. market_object = gromit.ns['/Assets/Energy/CME CL']
  103.  
  104. # Lets try and get the prices for this future. If you were to click on 'Settlements' from the web page
  105. # you will see a table which the contract months that are available and the settlement prices in the
  106. # column 'Settle'. You can move the date dropdown to go back time.
  107.  
  108. # The prices are stored in a time series, which is an ordered dictionary of date, curve pairs.
  109. # We can select a day's price (if the data is there) using some handy function calls.
  110.  
  111. market_date = datetime.date(2018, 2, 21)
  112. price_ts = ts_object(gromit.ns, 'Energy/CMECLfuts')
  113. price_curve = price_ts.Value(market_date)
  114.  
  115. print('Prices:', price_curve)
  116.  
  117. #Note that only valid days in the past will work when asking for data. The data you see shoud
  118. #match what you see on the Nymex website. So now you have the underlying prices for a market.
  119. #To get to the option prices you'll need a companion time series
  120. # Energy/CMECLopts
  121.  
  122. opt_ts = ts_object(gromit.ns, self.Input1())
  123. option_curve = opt_ts.Value(market_date)
  124.  
  125. print('Option prices:', option_curve)
  126.  
  127. # The format of the option data is (is_call, strike, option price). Recall that given these things
  128. #plus some additional information and our BS function we can turn this information into a volatility
  129.  
  130. # Aside from printing these python objects, what other functionality do they have? After executing
  131. # this script it puts the local variables into the IPython shell. You can ask the objects for
  132. # their type (ex. type(market_objet)). That should print out the module name which will be in a folder
  133. # /wst/mktint/nrgfut.py (see the left tree)
  134.  
  135. # In that module (and base classes) will be a lot of useful functionality. One thing that we need to
  136. # find is when do options expire. Handily
  137.  
  138. exp_code = ContractTenor('Dec18')
  139. exp_date = market_object.ExpirationDate(exp_code)
  140.  
  141. print('Expiration:', exp_date)
  142.  
  143. print(type(option_curve))
  144. method_list = [func for func in dir(option_curve) if callable(getattr(option_curve, func))]
  145. print(method_list)
  146. print(option_curve.values())
  147.  
  148. # shit code is shit code
  149.  
  150. values = option_curve.values()
  151. dates = option_curve.tenors()
  152. price_curve = price_curve.values()
  153. strike_prices = []
  154. new_dates = []
  155. global prices
  156. global volatilities
  157. for index,i in enumerate(values):
  158. for x in i:
  159. volatility = self.getVolitility(x[0],float(x[1]),float(x[2]),datetime.datetime.strptime(str(dates[index]),'%b%y').date(),'test')
  160. print(volatility)
  161. print('vol')
  162. if(volatility != False and volatility != None):
  163. volatilities.append(volatility)
  164. prices.append(price_curve[index])
  165. strike_prices.append(x[1])
  166. new_dates.append(datetime.datetime.strptime(str(dates[index]),'%b%y').date())
  167.  
  168. mean = sum(prices)
  169. std = numpy.std(prices)
  170. print('here')
  171. for index,volitility in enumerate(volatilities):
  172. if volitility != False:
  173. if x[0]:
  174. self.checkCallPrice(prices[index], mean, std, strike_prices[index], new_dates[index])
  175. else:
  176. self.checkPutPrice(prices[index], mean, std, strike_prices[index], new_dates[index])
  177.  
  178. class AppController(SimpleAppController):
  179. '''
  180. The controller is the part of the mvc framework that connects the model and the view. This where you would put things like
  181. action to operate when buttons are clicked.
  182.  
  183. '''
  184.  
  185. def __init__(self, model):
  186. self.model = model
  187.  
  188.  
  189. def getStockStuff(self):
  190. print("ran")
  191. stock_stuff = self.model.calcStockStuff()
  192. return stock_stuff
  193.  
  194.  
  195. #
  196. # The last part of the puzzle is the view. This is simply a representation of the view where the layout id described in python objects.
  197. #
  198. # There is a main wiki page for UI in general (https://wst.wsq.io/wst/wiki/training/gromit-simple)
  199. #
  200. # But I suggest you concentrate on the the bits that are crucial:
  201. #
  202. # What are all the widgets and how do I lay them out (the bits under Components overview)
  203. # And even better sume examples
  204. #
  205. # wst/ui/examples/* (not everything in there will run, so ignore what does not)
  206. #
  207. # But let me draw your attention to:
  208. #
  209. # wst/ui/examples/app_controls.py - best way to see what you have in your tool bag (see 06 to fully digest the code)
  210. # wst/ui/examples/app_chart_* -
  211. # wst/ui/examples/app_spreadsheet_*
  212. #
  213. # Please ignore anything that has to do with 'glint' which is an under-development next version of ui UI plantform
  214. #
  215.  
  216. def volatility_plot(model):
  217.  
  218. #We use matplotlib to to generate a chart. This is a popular python package.
  219. global prices
  220. global volatilities
  221. model.calcStockStuff()
  222. min_price = min(prices)
  223. max_price = max(prices)
  224. min_vol = min(volatilities)
  225. max_vol = max(volatilities)
  226. fig = plt.figure()
  227. # X, Y, Z = axes3d.get_test_data(0.05)
  228. # ax.plot_surface(X, Y, rstride=8, cstride=8, alpha=0.3)
  229.  
  230. # for index,price in enumerate(Model.prices):
  231. # cset = ax.contour(X, Y,
  232.  
  233. # cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
  234. # cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
  235. # cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
  236.  
  237. plt.plot(prices, volatilities)
  238. plt.ylabel('Volatility')
  239. plt.xlabel('Strike Price')
  240. # ax.set_xlabel('Strike')
  241. # ax.set_xlim(min_price, max_price)
  242. # ax.set_ylabel('Implied Volatility')
  243. # ax.set_ylim(min_vol, max_vol)
  244.  
  245. #Unfortunately you can't see it in your browser, the package shows the image on the remote machine
  246. #in amazon
  247. plt.show()
  248.  
  249. #But we can create a temporary image and embed it directly into an html page
  250. plt.savefig('temp.png')
  251. import base64
  252. data_uri = base64.b64encode(open('temp.png', 'rb').read()).decode('utf-8').replace('\n','')
  253. img_tag = '<img src="data:image/png;base64,{0}">'.format(data_uri)
  254. html = '<html>Volatility<b>%s<b></html>' % img_tag
  255.  
  256. return html
  257.  
  258. def pl_plot():
  259.  
  260. #We use matplotlib to to generate a chart. This is a popular python package.
  261. fig = plt.figure()
  262. ax = fig.gca(projection='3d')
  263. X, Y, Z = axes3d.get_test_data(0.05)
  264. ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
  265. cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
  266. cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
  267. cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
  268.  
  269. ax.set_xlabel('X')
  270. ax.set_xlim(-40, 40)
  271. ax.set_ylabel('Y')
  272. ax.set_ylim(-40, 40)
  273. ax.set_zlabel('Z')
  274. ax.set_zlim(-100, 100)
  275.  
  276. #Unfortunately you can't see it in your browser, the package shows the image on the remote machine
  277. #in amazon
  278. plt.show()
  279.  
  280. #But we can create a temporary image and embed it directly into an html page
  281. plt.savefig('temp.png')
  282. import base64
  283. data_uri = base64.b64encode(open('temp.png', 'rb').read()).decode('utf-8').replace('\n','')
  284. img_tag = '<img src="data:image/png;base64,{0}">'.format(data_uri)
  285. html = '<html>P&L<b>%sFooter<b></html>' % img_tag
  286.  
  287. return html
  288.  
  289. def greeks_plot(model):
  290.  
  291. #We use matplotlib to to generate a chart. This is a popular python package.
  292. global prices
  293. global volatilities
  294. model.calcStockStuff()
  295. fig = plt.figure()
  296. ax = fig.gca(projection='3d')
  297. X, Y, Z = axes3d.get_test_data(0.05)
  298. ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
  299. cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
  300. cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
  301. cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
  302.  
  303. ax.set_xlabel('X')
  304. ax.set_xlim(-40, 40)
  305. ax.set_ylabel('Y')
  306. ax.set_ylim(-40, 40)
  307. ax.set_zlabel('Z')
  308. ax.set_zlim(-100, 100)
  309.  
  310. #Unfortunately you can't see it in your browser, the package shows the image on the remote machine
  311. #in amazon
  312. plt.show()
  313.  
  314. #But we can create a temporary image and embed it directly into an html page
  315. plt.savefig('delta_temp.png')
  316. import base64
  317. delta_data_uri = base64.b64encode(open('delta_temp.png', 'rb').read()).decode('utf-8').replace('\n','')
  318. delta_img_tag = '<img src="data:image/png;base64,{0}">'.format(data_uri)
  319. html = '<html>Greeks<b>Delta%s<b></html>' % delta_img_tag
  320.  
  321. return html
  322.  
  323. class MainView(SimpleAppView):
  324. def __init__(self,model):
  325. content = VList([
  326. '<h2>Volatility, P&L, and the Greeks</h2>',
  327. Button('Stock', on_click=partial(show_view, model, './#/stock')),
  328. Button('Volatility', on_click=partial(show_view, model, './#/volatility')),
  329. Button('P&L', on_click=partial(show_view, model, './#/pl')),
  330. Button('Greeks', on_click=partial(show_view, model, './#/greeks')),
  331.  
  332. #We can embed html content directly into an IFrame
  333. IFrame(src=model.target_url, css_style="height: 800px;max-width:100vw;"),
  334. volatility_view
  335. ])
  336. super().__init__(content, view_name="index")
  337.  
  338. class StockView(SimpleAppView):
  339. def __init__(self,model,inner_model,controller):
  340. content = [
  341. Row([
  342. Col(size=3, content=Label('Stock Price:')),
  343. Col(size=3, content=TextField(inner_model.Input1)),
  344. Col(size=6, content=Button('Calculate', on_click=controller.getStockStuff)),
  345. ]),
  346. ]
  347. super().__init__(content, view_name="stock")
  348.  
  349.  
  350.  
  351. def volatility_view(model):
  352. html = volatility_plot(model)
  353.  
  354. return html
  355.  
  356. def pl_view():
  357. html = pl_plot()
  358.  
  359. return html
  360.  
  361. def greeks_view(model):
  362. html = greeks_plot(model)
  363.  
  364. return html
  365.  
  366. class VolatilityView(SimpleAppView):
  367. def __init__(self,model,inner_model,controller):
  368. content = [
  369. volatility_view(inner_model)
  370. ]
  371. super().__init__(content, view_name='volatility')
  372.  
  373. class PLView(SimpleAppView):
  374. def __init__(self,model,inner_model,controller):
  375. content = [
  376. pl_view()
  377. ]
  378. super().__init__(content, view_name='pl')
  379.  
  380.  
  381. class GreeksView(SimpleAppView):
  382. def __init__(self,model,inner_model,controller):
  383. content = [
  384. greeks_view(inner_model)
  385. ]
  386. super().__init__(content, view_name='greeks')
  387.  
  388.  
  389.  
  390. def main():
  391.  
  392. # Here is where the model, controller and view are instantiated and then they launch an async web page
  393.  
  394. model = ViewModel()
  395. inner_model = gromit.ns.new(Model)
  396.  
  397. controller = AppController(inner_model)
  398. #app_views = create_views(controller)
  399.  
  400. app = SimpleApp(views=[
  401. MainView(model),
  402. StockView(model,inner_model,controller),
  403. VolatilityView(model,inner_model,controller),
  404. PLView(model,inner_model,controller),
  405. GreeksView(model,inner_model,controller)
  406. ],
  407. title="Volitiliy Calculator",
  408. app_style="fluid-nohome-nofooter",
  409. show_db=False
  410. )
  411. app.run()
  412.  
  413. return controller
  414.  
  415.  
  416. if __name__ == '__main__':
  417.  
  418. # While the app is running you can still use the IPython shell. With a reference to the controller you can
  419. # do things like inspecting your model to make sure it's doing what you want
  420.  
  421. # ex. controller.model.Sum() should show you the same number on screen
  422. # and if you were to do something like call
  423. # controler.model.Input1.set_value(20) you should see you UI updates
  424. #
  425.  
  426. controller = main()
Add Comment
Please, Sign In to add comment