opt_serve.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. # -*- coding: utf-8 -*-
  2. import sys, traceback
  3. import logging
  4. import os
  5. import ast
  6. import urllib, urllib2, cookielib
  7. import datetime, time
  8. import re
  9. import json
  10. import cherrypy
  11. import hashlib
  12. import uuid
  13. import redis
  14. import json
  15. import optcal
  16. import ConfigParser
  17. import portfolio
  18. from comms.alert_bot import AlertHelper
  19. from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
  20. from ws4py.websocket import WebSocket
  21. from ws4py.websocket import EchoWebSocket
  22. from sets import Set
  23. import thread
  24. class QServer(object):
  25. config = None
  26. r_conn = None
  27. def __init__(self, r_conn, config):
  28. super(QServer, self).__init__()
  29. QServer.r_conn = r_conn
  30. QServer.config = config
  31. #print QServer.r_conn
  32. @cherrypy.expose
  33. def index(self):
  34. #s_line = 'welcome!'
  35. #r_host = cherrypy.request.app.config['redis']['redis.server']
  36. #r_port = cherrypy.request.app.config['redis']['redis.port']
  37. #r_db = cherrypy.request.app.config['redis']['redis.db']
  38. #r_sleep = cherrypy.request.app.config['redis']['redis.sleep']
  39. #rs = redis.Redis(r_host, r_port, r_db)
  40. rs = QServer.r_conn
  41. s_line = rs.info()
  42. html =''
  43. for k, v in cherrypy.request.app.config.iteritems():
  44. html = html + '<dt>%s</dt><dd>%s</dd>' % (k, v)
  45. impl_link = "<a href=./opt_implv><img src='public/chart.png' width='42' height=42'/>options implied vol curves</a>"
  46. pos_link = "<a href=./ws_position_chart><img src='public/moneyup.png' width='42' height='42'/>Positions</a>"
  47. stackpos_link = "<a href=./ws_position_chart_ex><img src='public/scale.png' width='42' height='42' />Positions (Stacked View)</a>"
  48. bubble_link = "<a href=./port_bubble_chart><img src='public/Market-Risk-Icon.png' width='42' height='42' />Risk Distributions</a>"
  49. html = ''
  50. s_line = ''
  51. return """<html><body><li>%s</li><li>%s</li><li>%s</li><li>%s</li><br><dl>%s</dl></br>%s</body></html>""" % (bubble_link, impl_link, pos_link, stackpos_link, html, s_line)
  52. @cherrypy.expose
  53. def opt_chains(self):
  54. r_host = cherrypy.request.app.config['redis']['redis.server']
  55. r_port = cherrypy.request.app.config['redis']['redis.port']
  56. r_db = cherrypy.request.app.config['redis']['redis.db']
  57. r_sleep = cherrypy.request.app.config['redis']['redis.sleep']
  58. opt_chains = cherrypy.request.app.config['redis']['redis.datastore.key.option_chains']
  59. rs = redis.Redis(r_host, r_port, r_db)
  60. opt_chain_tmpl = '%s%s/opt-chains-tmpl.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  61. f = open(opt_chain_tmpl)
  62. html_tmpl = f.read()
  63. s_dict = rs.get(opt_chains)
  64. matrix = json.loads(s_dict)
  65. strike = matrix.keys()[0]
  66. print matrix
  67. num_months = len(matrix[strike])
  68. s = '["strike",'
  69. # for i in range(num_months):
  70. # s = s + "'P-%s', 'C-%s', " % (matrix[strike].keys()[i], matrix[strike].keys()[i])
  71. s = s + '],'
  72. for month, strikes in sorted(matrix.iteritems()):
  73. l = ''
  74. for strike, cp in sorted(strikes.iteritems()):
  75. l = l + '[%s,%s,%s,%s,%s],' % (strike, cp['P']['0'], cp['P']['1'], cp['P']['2'], cp['P']['3'])
  76. s = s + l + '],\n'
  77. print s
  78. html_tmpl = html_tmpl.replace('{{{data}}}', s)
  79. return html_tmpl
  80. @cherrypy.expose
  81. def opt_implv(self):
  82. #r_host = cherrypy.request.app.config['redis']['redis.server']
  83. #r_port = cherrypy.request.app.config['redis']['redis.port']
  84. #r_db = cherrypy.request.app.config['redis']['redis.db']
  85. #r_sleep = cherrypy.request.app.config['redis']['redis.sleep']
  86. opt_implv = cherrypy.request.app.config['redis']['redis.datastore.key.option_implv']
  87. #rs = redis.Redis(r_host, r_port, r_db)
  88. rs = QServer.r_conn
  89. opt_implv_tmpl = '%s%s/opt-chains-tmpl.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  90. f = open(opt_implv_tmpl)
  91. html_tmpl = f.read()
  92. s_dict = rs.get(opt_implv)
  93. # sample value
  94. # {u'25400': {u'20150828': {u'P': [u'null', 1400.0], u'C': [0.21410911336791702, 29.0]}, u'20150929': {u'P': [u'null', u'null'], u'C': [0.1934532406732742, 170.0]}}, ...
  95. matrix = json.loads(s_dict)
  96. strike = matrix.keys()[0]
  97. print matrix
  98. num_months = len(matrix[strike])
  99. s = '["strike",'
  100. sorted_months = sorted(matrix[strike].keys())
  101. for i in range(num_months):
  102. s = s + "'P-%s', 'C-%s', " % (sorted_months[i], sorted_months[i])
  103. s = s + '],'
  104. for strike, items in sorted(matrix.iteritems()):
  105. s = s + '[%s,' % str(strike)
  106. l = ''
  107. for month, cp in sorted(items.iteritems()):
  108. print month, cp
  109. l = l + ''.join('%s,%s,' % (cp['P'][0], cp['C'][0]))
  110. s = s + l + '],\n'
  111. html_tmpl = html_tmpl.replace('{{{data}}}', s)
  112. s = '["strike",'
  113. for i in range(num_months):
  114. s = s + "'P-%s', 'C-%s', " % (sorted_months[i], sorted_months[i])
  115. s = s + '],'
  116. for strike, items in sorted(matrix.iteritems()):
  117. s = s + '[%s,' % str(strike)
  118. l = ''
  119. for month, cp in sorted(items.iteritems()):
  120. l = l + ''.join('%s,%s,' % (cp['P'][1], cp['C'][1]))
  121. s = s + l + '],\n'
  122. print 'sorted months' + sorted_months[0]
  123. html_tmpl = html_tmpl.replace('{{{dataPremium}}}', s)
  124. html_tmpl = html_tmpl.replace('{{{thisContractMonth}}}', sorted_months[0])
  125. return html_tmpl
  126. @cherrypy.expose
  127. def opt_implv_ex(self):
  128. #r_host = cherrypy.request.app.config['redis']['redis.server']
  129. #r_port = cherrypy.request.app.config['redis']['redis.port']
  130. #r_db = cherrypy.request.app.config['redis']['redis.db']
  131. #r_sleep = cherrypy.request.app.config['redis']['redis.sleep']
  132. opt_implv = cherrypy.request.app.config['redis']['redis.datastore.key.option_implv']
  133. #rs = redis.Redis(r_host, r_port, r_db)
  134. rs = QServer.r_conn
  135. opt_implv_tmpl = '%s%s/opt-chains-ex-tmpl.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  136. f = open(opt_implv_tmpl)
  137. html_tmpl = f.read()
  138. s_dict = rs.get(opt_implv)
  139. # sample value
  140. # {u'25400': {u'20150828': {u'P': [u'null', 1400.0], u'C': [0.21410911336791702, 29.0]}, u'20150929': {u'P': [u'null', u'null'], u'C': [0.1934532406732742, 170.0]}}, ...
  141. matrix = json.loads(s_dict)
  142. strike = matrix.keys()[0]
  143. print matrix
  144. num_months = len(matrix[strike])
  145. s = '["strike",'
  146. sorted_months = sorted(matrix[strike].keys())
  147. for i in range(num_months):
  148. s = s + "'P-%s', 'C-%s', " % (sorted_months[i], sorted_months[i])
  149. s = s + '],'
  150. for strike, items in sorted(matrix.iteritems()):
  151. s = s + '[%s,' % str(strike)
  152. l = ''
  153. for month, cp in sorted(items.iteritems()):
  154. print month, cp
  155. l = l + ''.join('%s,%s,' % (cp['P'][0], cp['C'][0]))
  156. s = s + l + '],\n'
  157. html_tmpl = html_tmpl.replace('{{{data}}}', s)
  158. s = '[{label:"strikes",type:"number"},'
  159. for i in range(num_months):
  160. s = s + "{label: 'P-%s', type:'number'},\
  161. {label: 'Pb-%s', id:'i0', type:'number', role:'interval'},\
  162. {label: 'Pa-%s', id:'i0', type:'number', role:'interval'},\
  163. {label: 'C-%s', type:'number', },\
  164. {label: 'Cb-%s', id:'i0', type:'number', role:'interval'},\
  165. {label: 'Ca-%s', id:'i0',type:'number', role:'interval'},"\
  166. % (sorted_months[i], sorted_months[i],sorted_months[i], sorted_months[i],sorted_months[i], sorted_months[i])
  167. s = s + '],'
  168. for strike, items in sorted(matrix.iteritems()):
  169. s = s + '[%s,' % str(strike)
  170. l = ''
  171. for month, cp in sorted(items.iteritems()):
  172. l = l + ''.join('%s,%s,%s,%s,%s,%s,' % (cp['P'][1], cp['P'][2],cp['P'][3],cp['C'][1],cp['C'][2],cp['C'][3]))
  173. s = s + l + '],\n'
  174. html_tmpl = html_tmpl.replace('{{{dataPremium}}}', s)
  175. html_tmpl = html_tmpl.replace('{{{thisContractMonth}}}', sorted_months[0])
  176. return html_tmpl
  177. @cherrypy.expose
  178. def ws_cal_implvol(self, s, x, cp, ed, xd, r, d, v, p, out='iv'):
  179. try:
  180. #spot, strike, callput, evaldate, exdate, rate, div, vol, premium
  181. rs = optcal.cal_implvol(float(s), float(x), cp, ed, xd, float(r), float(d), float(v), float(p))
  182. return str(rs['imvol'])
  183. except:
  184. return
  185. @cherrypy.expose
  186. def ws_cal_option(self, s, x, cp, ed, xd, r, d, v, out='npv'):
  187. #spot, strike, callput, evaldate, exdate, rate, div, vol
  188. keys = ['npv', 'delta', 'gamma', 'theta', 'vega'];
  189. try:
  190. rs = optcal.cal_option(float(s), float(x), cp, ed, xd, float(r), float(d), float(v))
  191. if out == 'csv':
  192. logging.debug('ws_cal_option: ' + ','.join(str(rs[s]) for s in keys))
  193. return ','.join(str(rs[s]) for s in keys)
  194. elif out == 'json':
  195. return json.dumps(rs)
  196. else:
  197. return str(rs[out])
  198. except:
  199. #exc_type, exc_value, exc_traceback = sys.exc_info()
  200. return traceback.format_exc()
  201. @cherrypy.expose
  202. def ws_get_hist_implv(self, dataAt):
  203. # given a date string YYMMDDHHMM, this routine returns an array of
  204. # implied vols arranged in a format like the below
  205. # [["strike",'P-20150828', 'C-20150828', 'P-20150929', 'C-20150929', ],
  206. # [21800,0.29153118077,null,0.241032122988,null,],
  207. # [22000,0.284002011642,null,0.238145680311,null,],
  208. # [22200,0.270501965746,null,0.222647164832,null,]]
  209. pass
  210. @cherrypy.expose
  211. def ws_market_data(self, r_ckey, fid):
  212. if str(fid).upper() == 'ALL':
  213. return QServer.r_conn.get(r_ckey)
  214. val = QServer.r_conn.get(r_ckey)
  215. if val is None:
  216. return 'invalid request. Check your input again!'
  217. dict = json.loads(QServer.r_conn.get(r_ckey))
  218. return str(dict[fid])
  219. @cherrypy.expose
  220. def ws_position_chart(self):
  221. p = portfolio.PortfolioManager(config)
  222. p.retrieve_position()
  223. opt_pos_chart_tmpl = '%s%s/opt-pos-chart-tmpl.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  224. f = open(opt_pos_chart_tmpl)
  225. html_tmpl = f.read()
  226. html_tmpl = html_tmpl.replace('{{{dataPCpos}}}', p.get_grouped_options_str_array())
  227. html_tmpl = html_tmpl.replace('{{{dataTablePos}}}', p.get_tbl_pos_csv())
  228. html_tmpl = html_tmpl.replace('{{{option_months}}}', ''.join(('%s, ' % m) for m in p.get_traded_months()))
  229. v = p.group_pos_by_right()
  230. html_tmpl = html_tmpl.replace('{{{PRvsCR}}}}', '%0.2f : %0.2f' % (v[0][1], v[1][1]))
  231. #print p.get_portfolio_summary()
  232. #html_tmpl = html_tmpl.replace('{{{pos_summary}}}', ''.join('<li>%s: %s</li>' % (x[0],x[1]) for x in p.get_portfolio_summary() ))
  233. #print '\n'.join('%s:\t\t%s' % (k,v) for k,v in sorted(json.loads(DataMap.rs.get(port_key)).iteritems()))
  234. return html_tmpl
  235. #
  236. # ws_position_chart_ex
  237. #
  238. #
  239. # this is an extended version of ws_position_chart
  240. # shows options by month, strikes, right instead of just strikes and right
  241. # 2016-03-23
  242. def generate_garray(self, plist):
  243. # generate a key map with month-right-strike
  244. # example: ('20160330-C-20000', 0.2),...
  245. klist = map(lambda x: ('%s-%s-%s' % (x[2], x[3], x[4]), float(x[5])/50.0*float(x[6])), plist)
  246. # for e in sorted(klist):
  247. # print e
  248. # get the unique keys in klist
  249. unique_keys= Set(map(lambda x:x[0], klist))
  250. strikes =[e for e in Set(map(lambda x:x[4], plist))]
  251. # sort the months in ascending order
  252. months = sorted([e for e in Set(map(lambda x:x[2], plist))])
  253. print klist
  254. print strikes
  255. # print months
  256. # print len(klist), len(s)
  257. # group and sum position by month, strike, right
  258. grouped_pos = []
  259. for elem in unique_keys:
  260. grp1 = filter(lambda x: x[0] == elem, klist)
  261. print grp1
  262. # sum items with same key
  263. # example: [('20160330-P-19600', -1.0), ('20160330-P-19600', 0.2)]
  264. grouped_pos.append( grp1[0] if len(grp1) == 1 else reduce(lambda x,y: (x[0], x[1]+y[1]), grp1) )
  265. print '---'
  266. print grouped_pos
  267. garr = {}
  268. def init_garray(x):
  269. garr[x] = {}
  270. map(init_garray, sorted(strikes))
  271. print garr
  272. def set_garray(x):
  273. vals = x[0].split(('-'))
  274. if vals[0] == months[0]:
  275. if vals[1] == 'C':
  276. garr[vals[2]]['NEAR_C'] = x[1]
  277. else:
  278. garr[vals[2]]['NEAR_P'] = x[1]
  279. elif vals[0] == months[1]:
  280. if vals[1] == 'C':
  281. garr[vals[2]]['FAR_C'] = x[1]
  282. else:
  283. garr[vals[2]]['FAR_P'] = x[1]
  284. # find all C of near month
  285. map(set_garray, grouped_pos)
  286. print garr
  287. s=''
  288. for k, v in garr.iteritems():
  289. s+= '[%s, %s,%s,%s,%s],' % (k, v['NEAR_P'] if 'NEAR_P' in v else '0',
  290. v['NEAR_C'] if 'NEAR_C' in v else '0',
  291. v['FAR_P'] if 'FAR_P' in v else '0',
  292. v['FAR_C'] if 'FAR_C' in v else '0', )
  293. return s
  294. def generate_garray_ex(self, plist):
  295. #[['HSI', 'FUT', '20170126', 'None', '0', '50.0', '0.0000', '0.0000'],
  296. # ['HSI', 'OPT', '20170126', 'C', '23000', '50.0', '-4.0000', '3240.3350'], ['HSI', 'OPT', '20170126', 'P', '22600', '50.0', '-1.0000', '1330.9600'], ['HSI', 'OPT', '20170227', 'C', '23400', '50.0', '-2.0000', '9880.9600'], ['HSI', 'OPT', '20170227', 'C', '23600', '50.0', '-1.0000', '9530.9600'], ['HSI', 'OPT', '20170227', 'P', '20200', '50.0', '-3.0000', '980.9600'], ['HSI', 'OPT', '20170227', 'P', '20400', '50.0', '-1.0000', '7664.2933'], ['HSI', 'OPT', '20170227', 'P', '21800', '50.0', '-3.0000', '5197.6267'], ['MHI', 'FUT', '20170126', 'None', '0', '10.0', '5.0000', '230459.6680']]
  297. # generate a key map with month-right-strike
  298. # example: ('20160330-C-20000', 0.2),...
  299. #klist = map(lambda x: ('%s-%s-%s' % (x[2], x[3] if x[3] <> 'None' else 'F', x[4]), float(x[5])/50.0*float(x[6])), plist)
  300. # 2017 - handle futures price
  301. def getX(x):
  302. val = x[4] if x[3] <> 'None' else str(int(round(float(x[7])/ float(x[5]),-1)))
  303. # print val
  304. return val
  305. plist = filter(lambda x: int(float(x[6])) <> 0, plist)
  306. klist = map(lambda x: ('%s-%s-%s' % (x[2], x[3] if x[3] <> 'None' else 'F', getX(x)), float(x[5])/50.0*float(x[6])), plist)
  307. # for e in sorted(klist):
  308. # print e
  309. # get the unique keys in klist
  310. unique_keys= Set(map(lambda x:x[0], klist))
  311. #strikes =[e for e in Set(map(lambda x:x[4], plist))]
  312. # 2017
  313. strikes = [e for e in Set(map(lambda x:getX(x), plist))]
  314. # sort the months in ascending order
  315. months = sorted([e for e in Set(map(lambda x:x[2], plist))])
  316. print klist
  317. print strikes
  318. # print months
  319. # print len(klist), len(s)
  320. # group and sum position by month, strike, right
  321. grouped_pos = []
  322. for elem in unique_keys:
  323. grp1 = filter(lambda x: x[0] == elem, klist)
  324. print grp1
  325. # sum items with same key
  326. # example: [('20160330-P-19600', -1.0), ('20160330-P-19600', 0.2)]
  327. grouped_pos.append( grp1[0] if len(grp1) == 1 else reduce(lambda x,y: (x[0], x[1]+y[1]), grp1) )
  328. print '---'
  329. print grouped_pos
  330. garr = {}
  331. def init_garray(x):
  332. garr[x] = {}
  333. map(init_garray, sorted(strikes))
  334. print garr
  335. def set_garray(x):
  336. vals = x[0].split(('-'))
  337. if vals[0] == months[0]:
  338. if vals[1] == 'C':
  339. garr[vals[2]]['NEAR_C'] = x[1]
  340. elif vals[1] =='P':
  341. garr[vals[2]]['NEAR_P'] = x[1]
  342. else:
  343. garr[vals[2]]['NEAR_F'] = x[1]
  344. elif vals[0] == months[1]:
  345. if vals[1] == 'C':
  346. garr[vals[2]]['FAR_C'] = x[1]
  347. elif vals[1] =='P':
  348. garr[vals[2]]['FAR_P'] = x[1]
  349. else:
  350. garr[vals[2]]['FAR_F'] = x[1]
  351. # find all C of near month
  352. map(set_garray, grouped_pos)
  353. print garr
  354. s=''
  355. for k, v in garr.iteritems():
  356. s+= '[%s, %s,%s,%s,%s,%s,%s],' % (k, v['NEAR_P'] if 'NEAR_P' in v else '0',
  357. v['NEAR_C'] if 'NEAR_C' in v else '0',
  358. v['FAR_P'] if 'FAR_P' in v else '0',
  359. v['FAR_C'] if 'FAR_C' in v else '0',
  360. v['NEAR_F'] if 'NEAR_F' in v else '0',
  361. v['FAR_F'] if 'FAR_F' in v else '0', )
  362. return s
  363. @cherrypy.expose
  364. def ws_position_chart_ex(self):
  365. p = portfolio.PortfolioManager(config)
  366. p.retrieve_position()
  367. opt_pos_chart_tmpl = '%s%s/opt-pos-chart-stacked-tmpl.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  368. f = open(opt_pos_chart_tmpl)
  369. html_tmpl = f.read()
  370. #html_tmpl = html_tmpl.replace('{{{dataPCpos}}}', self.generate_garray(p.get_tbl_pos_list()))
  371. # 2017 - handles futures
  372. html_tmpl = html_tmpl.replace('{{{dataPCpos}}}', self.generate_garray_ex(p.get_tbl_pos_list()))
  373. html_tmpl = html_tmpl.replace('{{{dataTablePos}}}', p.get_tbl_pos_csv())
  374. html_tmpl = html_tmpl.replace('{{{option_months}}}', ''.join(('%s, ' % m) for m in p.get_traded_months()))
  375. v = p.group_pos_by_right()
  376. html_tmpl = html_tmpl.replace('{{{PRvsCR}}}}', '%0.2f : %0.2f' % (v[0][1], v[1][1]))
  377. #print p.get_portfolio_summary()
  378. #html_tmpl = html_tmpl.replace('{{{pos_summary}}}', ''.join('<li>%s: %s</li>' % (x[0],x[1]) for x in p.get_portfolio_summary() ))
  379. #print '\n'.join('%s:\t\t%s' % (k,v) for k,v in sorted(json.loads(DataMap.rs.get(port_key)).iteritems()))
  380. return html_tmpl
  381. @cherrypy.expose
  382. def ws_position_summary(self):
  383. p = portfolio.PortfolioManager(config)
  384. keys = [("delta_1percent","number"),("delta_all","number"),("delta_c","number"),("delta_p","number"),\
  385. ("theta_1percent","number"),("theta_all","number"),("theta_c","number"),("theta_p","number"),\
  386. ("unreal_pl","number"),("last_updated","string"),("status","string")]
  387. d = p.get_portfolio_summary()
  388. dict= {}
  389. dict['cols'] = [{'label': x[0], 'type': x[1]} for x in keys]
  390. dict['rows'] = [{'v': d[x[0]]} for x in keys]
  391. print json.dumps(dict)
  392. return json.dumps(dict)
  393. @cherrypy.expose
  394. def ws_recal_pos(self, force_refresh=False):
  395. p = portfolio.PortfolioManager(config)
  396. if force_refresh:
  397. p.retrieve_position()
  398. l_gmap = p.recal_port()
  399. print l_gmap
  400. return json.dumps(l_gmap)
  401. @cherrypy.expose
  402. def ws_pos_csv(self):
  403. p = portfolio.PortfolioManager(config)
  404. p.retrieve_position()
  405. s = "%s" % p.get_tbl_pos_csv_old()
  406. #s = "%s" % p.get_tbl_pos_csv()
  407. #print s
  408. s = s.replace(',[', '').replace(']', '<br>')
  409. print s
  410. return s[1:len(s)-3]
  411. @cherrypy.expose
  412. def getSHquote(self, qs):
  413. #http://api.money.126.net/data/feed/0000001,1399001,1399300
  414. #_ntes_quote_callback({"0000001":{"code": "0000001", "percent": 0.015468, "askvol1": 0, "askvol3": 0, "askvol2": 0, "askvol5": 0,
  415. # "askvol4": 0, "price": 2972.57, "open": 2978.03, "bid5": 0, "bid4": 0, "bid3": 0, "bid2": 0, "bid1": 0, "high": 3014.41, "low": 2929.0,
  416. #"updown": 45.28, "type": "SH", "bidvol1": 0, "status": 0, "bidvol3": 0, "bidvol2": 0, "symbol": "000001", "update": "2015/08/27 12:43:00",
  417. #"bidvol5": 0, "bidvol4": 0, "volume": 19800251400, "ask5": 0, "ask4": 0, "ask1": 0, "name": "\u4e0a\u8bc1\u6307\u6570", "ask3": 0, "ask2": 0,
  418. # "arrow": "\u2191", "time": "2015/08/27 12:42:57", "yestclose": 2927.29, "turnover": 204156106776} });
  419. url = 'http://api.money.126.net/data/feed/%s?callback=ne3587367b7387dc' % qs
  420. print url
  421. pg = urllib2.urlopen(url.encode('utf-8'))
  422. s = pg.read().replace('ne3587367b7387dc(', '')
  423. s = s[:len(s)-2]
  424. print s
  425. return s
  426. @cherrypy.expose
  427. def ws_port_summary(self):
  428. rs = QServer.r_conn
  429. ps_key = cherrypy.request.app.config['redis']['redis.datastore.key.port_summary']
  430. s_portsum = rs.get(ps_key)
  431. #dict = json.loads(s_portsum)
  432. return s_portsum
  433. @cherrypy.expose
  434. def ws_port_items(self):
  435. rs = QServer.r_conn
  436. key = cherrypy.request.app.config['redis']['redis.datastore.key.port_items']
  437. s_portitems = rs.get(key)
  438. #dict = json.loads(s_portsum)
  439. return s_portitems
  440. @cherrypy.expose
  441. def port_bubble_chart(self):
  442. s_data = self.ws_bubble_data()
  443. bubble_chart_tmpl = '%s%s/bubble-port.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  444. f = open(bubble_chart_tmpl)
  445. html_tmpl = f.read()
  446. html_tmpl = html_tmpl.replace('{{{bubble_data}}}', s_data)
  447. contract_month = eval(cherrypy.request.app.config['market']['option.underlying.month_price'])[0][0]
  448. html_tmpl = html_tmpl.replace('{{{FUT_CONTRACT}}}', 'HSI-%s-FUT-' % (contract_month))
  449. s_acctitems, last_updated, account_no = self.ws_acct_data()
  450. print s_acctitems, last_updated, account_no
  451. html_tmpl = html_tmpl.replace('{{{barAcct}}}', s_acctitems)
  452. html_tmpl = html_tmpl.replace('{{{account_no}}}', account_no)
  453. html_tmpl = html_tmpl.replace('{{{last_updated}}}', last_updated)
  454. return html_tmpl
  455. @cherrypy.expose
  456. def ws_bubble_data(self):
  457. # Tick Value Description
  458. # 5001 impl vol
  459. # 5002 delta
  460. # 5003 gamma
  461. # 5004 theta
  462. # 5005 vega
  463. # 5006 premium
  464. # 6001 avgCost
  465. # 6002 pos
  466. # 6003 totCost
  467. # 6004 avgPx
  468. # 6005 pos delta
  469. # 6006 pos theta
  470. # 6007 multiplier
  471. # 6009 curr_port_value
  472. # 6008 unreal_pl
  473. # 6020 pos value impact +1% vol change
  474. # 6021 pos value impact -1% vol change
  475. s_portitems = self.ws_port_items()
  476. litems = json.loads(s_portitems)
  477. #2018 fix - get rid of 'FUT' contracts
  478. litems = filter(lambda x: 'FUT' not in x['contract'], litems)
  479. # only interested in unrealized items, pos != 0
  480. ldict = filter(lambda x: x['6002'] <> 0, litems)
  481. lcontract = map(lambda x: x['contract'], ldict)
  482. lpos_delta = map(lambda x: x['6005'], ldict)
  483. lstrike = map(lambda x: x['contract'].split('-')[2], ldict)
  484. ltheta = map(lambda x: x['6006'], ldict)
  485. lupl = map(lambda x: x['6008'], ldict)
  486. colnames = "[['contract', 'strike', 'unreal PL', 'theta', 'delta'],"
  487. print '----------------------'
  488. s_data = colnames + ''.join('["%s",%s,%s,%s,%s],' % (lcontract[i], lstrike[i], lupl[i], ltheta[i], abs(lpos_delta[i])) for i in range(len(lcontract)))+ ']'
  489. return s_data
  490. @cherrypy.expose
  491. def ws_acct_data(self):
  492. rs = QServer.r_conn
  493. key = cherrypy.request.app.config['redis']['redis.datastore.key.acct_summary']
  494. s_acctitems = rs.get(key)
  495. acct_items = json.loads(s_acctitems)
  496. # full set of acctitems
  497. #["EquityWithLoanValue", 1910295.05, "#3366CC"],["FullMaintMarginReq", 467308.14, "#DC3912"],["TotalCashValue", 1910246.58, "#3366CC"],["AvailableFunds", 1326159.87, "#3366CC"],["LookAheadMaintMarginReq", 467308.14, "#DC3912"],["BuyingPower", 8841065.82, "#3366CC"],["Cushion", 0.755374, "#DC3912"],["ExcessLiquidity", 1442986.91, "#3366CC"],["LookAheadInitMarginReq", 584135.17, "#3366CC"],["GrossPositionValue", 67834.78, "#DC3912"],["LookAheadAvailableFunds", 1326159.87, "#3366CC"],["FullAvailableFunds", 1326159.87, "#3366CC"],["MaintMarginReq", 467308.14, "#DC3912"],["FullInitMarginReq", 584135.17, "#3366CC"],["AccruedCash", 48.47, "#DC3912"],["NetLiquidation", 1910295.05, "#3366CC"],["FullExcessLiquidity", 1442986.91, "#3366CC"],["LookAheadExcessLiquidity", 1442986.91, "#3366CC"],["InitMarginReq", 584135.17, "#3366CC"],]
  498. interested_keys = ['LookAheadInitMarginReq', 'NetLiquidation', 'AvailableFunds', 'AccruedCash', 'TotalCashValue' , 'last_updated', 'AccountType']
  499. dict = {}
  500. for k in interested_keys:
  501. dict[k] = acct_items[k]
  502. #if 'LookAheadNextChange' in dict.keys():
  503. # del(dict['LookAheadNextChange'])
  504. colnames = "[['Category', 'Value', { role: 'style' } ],"
  505. unwanted_cols = ['DayTradesRemaining','last_updated', 'AccountType']
  506. s_data = colnames + ''.join('["%s", %s, "%s"],' % (k, '%s'%(v[0]), '#3366CC' if float(v[0]) > 500000 else '#DC3912') if k not in unwanted_cols else '' for k, v in dict.iteritems() )+ ']'
  507. return (s_data, dict['last_updated'], dict['AccountType'][2])
  508. @cherrypy.expose
  509. def ws_msg_bot(self, msg):
  510. a = AlertHelper(self.config)
  511. a.post_msg(msg)
  512. @cherrypy.expose
  513. def ws(self):
  514. logging.info('at ws')
  515. # you can access the class instance through
  516. handler = cherrypy.request.ws_handler
  517. while handler.opened == False:
  518. logging.info( 'not opened')
  519. logging.info( 'opened')
  520. @cherrypy.expose
  521. def ws_entry(self):
  522. html = '%s%s/wstest.html' % (cherrypy.request.app.config['/']['tools.staticdir.root'], cherrypy.request.app.config['/static']['tools.staticdir.tmpl'])
  523. f = open(html)
  524. return f.read()
  525. class OptWebSocket(WebSocket):
  526. # def __init__(self):
  527. # logging.debug('instantiated.')
  528. def received_message(self, message):
  529. self.send(message.data, message.is_binary)
  530. logging.info('received %s' % message.data)
  531. # def opened(self):
  532. # logging.info('web socket opened')
  533. #self.send('hello')
  534. # while 1:
  535. # self.send('%f' % time.time(), False)
  536. # time.sleep(2)
  537. def opened(self):
  538. logging.info('web socket opened')
  539. def data_provider():
  540. while 1:
  541. # print ('%f' % time.time())
  542. # time.sleep(2)
  543. def cb():
  544. #for i in range(1, 200, 25):
  545. # yield "#" * i
  546. yield '%f' % time.time()
  547. self.send(cb())
  548. logging.info('--- here')
  549. time.sleep(2)
  550. thread.start_new_thread(data_provider())
  551. def closed(self, code, reason=None):
  552. print "Closed down", code, reason
  553. if __name__ == '__main__':
  554. # logging.basicConfig(filename = "log/opt.log", filemode = 'a',
  555. # level=logging.DEBUG,
  556. # format='%(asctime)s %(levelname)-8s %(message)s')
  557. #
  558. #
  559. # config = ConfigParser.ConfigParser()
  560. # config.read("config/app.cfg")
  561. # host = config.get("redis", "redis.server").strip('"').strip("'")
  562. # port = config.get("redis", "redis.port")
  563. # db = config.get("redis", "redis.db")
  564. # r_conn = redis.Redis(host,port,db)
  565. # cherrypy.quickstart(QServer(r_conn, config), '/', "config/app.cfg")
  566. if len(sys.argv) != 2:
  567. print("Usage: %s <config file>" % sys.argv[0])
  568. exit(-1)
  569. cfg_path= sys.argv[1:]
  570. config = ConfigParser.ConfigParser()
  571. if len(config.read(cfg_path)) == 0:
  572. raise ValueError, "Failed to open config file"
  573. logconfig = eval(config.get("opt_serve", "opt_serve.logconfig").strip('"').strip("'"))
  574. logconfig['format'] = '%(asctime)s %(levelname)-8s %(message)s'
  575. logging.basicConfig(**logconfig)
  576. host = config.get("redis", "redis.server").strip('"').strip("'")
  577. port = config.get("redis", "redis.port")
  578. db = config.get("redis", "redis.db")
  579. r_conn = redis.Redis(host,port,db)
  580. WebSocketPlugin(cherrypy.engine).subscribe()
  581. cherrypy.tools.websocket = WebSocketTool()
  582. cherrypy.quickstart(QServer(r_conn, config), '/', cfg_path[0])