#!/usr/bin/python -O # This program is Copyright (C) 2007 by Peter McCluskey. # Use this at your own risk. It is only designed for one special purpose. # It is released under the terms and conditions of GNU GPL license, # version 2 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) or # higher (http://www.gnu.org/copyleft/gpl.html). # # To configure, make sure that amm_quantity has the quantity you want for # each contract id that the program will use, and edit the contract_id_list # to list only the contract ids you want to trade (there are 2 # contract_id_list entries near the end of the program that you may need to # edit, one for play.intrade.com and the other for www.intrade.com) # Also, edit the variables trade_log_file_name through webmaster_email_addr # to values that are appropriate for your system. The two file names need # to be in directories you can write to. If you don't understand the remaining # three variables and don't need email reports of errors that cause the # program to give up, then set smtp_server to something invalid such as '???'. # # To test it with play.intrade.com, run it with something like this: #./intrade_amm.py --server=play --user=xxx --password=xxxxxxxx # import sys, re, string, os, math, time, getopt import xml.parsers.expat, urllib, smtplib, commands, signal, socket # # amm_quantity sets the order size to trade for each contract id # amm_quantity = { '565196' : 115, # DEM.PRES-GOVT.DEBT '565197' : 115, # NONDEM.PRES-GOVT.DEBT '565198' : 115, # DEM.PRES-TROOPS.IRAQ '565199' : 115, # NONDEM.PRES-TROOPS.IRAQ '565200' : 38, # DEM.PRES-OIL.FUTURES '565201' : 38, # DEM.PRES-T.BONDS '437134' : 10, '416496' : 1, # Democratic Party Nominee to win Nevadas Electoral College Votes in 2008 Election '68364' : 2, # Democratic Party Nominee to win Nevadas Electoral College Votes in 2008 Election, play sys '142210' : 2, # Adult Talkativeness. Men v Women., play sys '174323' : 2, # The Google Lunar X Prize to be won on/before 31 December 2012 '97129' : 1, '219617' : 1, # JAP.TARGET.DEC09.>25% '65543210' : 1, # bogus } trade_log_file_name = '/var/www/html/amm/amm_trade.log' msg_log_file_name = '/home/pcm/amm_msg.log' smtp_server = 'mail.myisp.com' from_email_addr = 'my_email_address' webmaster_email_addr = 'webmaster_email_address' def write_msg_log(msg1): fd = open(msg_log_file_name, 'a') fd.write(str(msg1) + " %s\n" % time.ctime()) def handle_error(msg1, warn_only = 0): write_msg_log(msg1) errormsg = '' body = "From: %s\nTo: %s\nSubject: intrade amm error\n\n%s %s" \ % (from_email_addr, webmaster_email_addr, time.ctime(), msg1) try: mailer = smtplib.SMTP(smtp_server) except socket.error, msg: errormsg = "error while trying to mail via server %s: %s\n" \ % (smtp_server, msg) try: err_dict = mailer.sendmail(from_email_addr, [webmaster_email_addr], body) except smtplib.SMTPException, msg: errormsg += 'Error sending mail: ' + `msg.__class__` if hasattr(msg, 'args'): errormsg = errormsg + ' ' + `msg.args` else: for (email, code_msg) in err_dict.items(): errormsg = errormsg + 'Error sending mail ' + `code_msg` + "\n" mailer.quit() if errormsg: write_msg_log('handle_error done %s' % errormsg) if not warn_only: raise NotImplementedError # # an Order is a bid or ask that is sent to Intrade # class Order: def __init__(self, is_buy, quantity, price, contract_id): self.is_buy = is_buy self.quantity = quantity self.quantity_remain = quantity if type(price) != type(''): price = '%.4g' % price self.limitprice = price self.contract_id = str(contract_id) def ContractID(self): return self.contract_id def SetID(self, id): self.order_id = id def ID(self): return self.order_id def Is_Buy(self): return self.is_buy def __str__(self): return "%-4s %d of %d %s @ %s" \ % (("Sell", "Buy")[self.is_buy], self.quantity_remain, self.quantity, self.contract_id, self.limitprice) __repr__ = __str__ def Apply(self, trade): self.quantity_remain = int(self.quantity_remain) - int(trade.Quantity()) if self.quantity_remain < 0: handle_error('Apply quantity ' + str(self)) def Remain_Qty(self): return self.quantity_remain def Price(self): return self.limitprice # # an OrderExecution is the result of a trade # class OrderExecution: def __init__(self, order_id, quantity, contract_id, side, price, msg_id, executionTime, order_dict): self.orderID = order_id try: self.order = order_dict[order_id] except KeyError: write_msg_log("known order ids %s\nWARNING!! Unknown order id %s" \ % (order_dict.keys(), order_id)) self.order = None ##handle_error("Unknown order id " + order_id) self.msg_id = msg_id self.quantity = int(quantity) self.contract_id = contract_id self.side = side self.price = price self.time = executionTime # verify it matches what was submitted? if self.order: self.order.Apply(self) def __str__(self): return "OrderID %s %s %s %s %s" \ % (self.orderID, self.side, self.quantity, self.contract_id, self.price) def executionTime(self): return self.time def Contract(self): return self.contract_id def From_Order(self): return self.order def Quantity(self): return self.quantity def Is_Buy(self): return self.side == 'B' shock_price_list = [ 49.9, 49.8, 49.7, 49.6, 49.5, 49.4, 49.3, 49.2, 49.0, 48.8, 48.6, 48.4, 48.2, 48.0, 47.6, 47.2, 46.6, 46.0, 45.2, 44.4, 43.6, 42.8, 42.0, 41.0, 40.0, 38.0, 36.0, 32.0, 26.0, 20.0, 16.0, 12.0, 8.0, 4.0, 1.0, ] MIN_SPREAD = 0.01 # # ContractAMM handles market making operations specific to one contract # class ContractAMM: def __init__(self, contract_id): self.contract_id = contract_id if contract_id in ('565200', '565201', '68364'): self.spread_factor = 0.05 self.price_list = shock_price_list else: self.spread_factor = 0.1 self.price_list = None self.counter = 0 self.min_value = 0 self.max_value = 100 try: self.quantity = amm_quantity[contract_id] except KeyError: handle_error('unknown contract id ' + contract_id) self.has_created_orders = 0 self.counter_restored = 0 self.partial_exec = [0,0] def Has_Orders(self): return self.has_created_orders def Has_Restored_Counter(self): return self.counter_restored # automated market maker algorithm # based on Robin Hanson's ifextropy.html paper def updateOrders(self, trade): if trade is None: dir = 0 # initial order creation else: mm_order = trade.From_Order() if mm_order is None: handle_error("bogus order " + str(mm_order)) if mm_order.Remain_Qty() > 0: return [] if mm_order.Is_Buy(): dir = 1 else: dir = -1 self.counter += dir counter = self.counter bid = self.Market_Maker_Price(counter + 0.5) ask = self.Market_Maker_Price(counter - 0.5) buy_order = Order(True, self.quantity - self.partial_exec[0], bid, self.contract_id) sell_order = Order(False, self.quantity - self.partial_exec[1], ask, self.contract_id) self.partial_exec = [0,0] #sys.stderr.write("Market_Maker orders changed to %s %s, counter %d for %d\n" % (bid,ask, counter, dir)) #print 'submit orders', buy_order, sell_order self.has_created_orders = 1 if abs(bid - ask) < MIN_SPREAD or bid < self.min_value + MIN_SPREAD \ or ask > self.max_value - MIN_SPREAD: if bid < 50: # too high/low to make a market return (sell_order, ) return (buy_order, ) return (buy_order, sell_order) def Market_Maker_Price(self, counter): if self.price_list: try: px = self.price_list[int(abs(counter))] except IndexError: px = 0 if counter < 0: px = 100 - px return px spread_factor = self.spread_factor px = 1.0/(1.0 + math.exp(spread_factor * counter)) #dist_from_limit = max(0.0001, min(abs(px), abs(1.0 - px))) #round_places = min(3, int(2 - math.log10(dist_from_limit))) round_places = 3 r = round(px, round_places) r_px = self.min_value + (self.max_value - self.min_value) * r # hack to handle limited precision with systems that only allow # prices to nearest 0.1: if r_px < 0.1/spread_factor: if r_px < MIN_SPREAD: write_msg_log('counter %s r_px %s' % (counter, r_px)) return 0 return self.Market_Maker_Price(counter - 1) - 0.1 elif r_px > 100-0.1/spread_factor: if r_px > 100-MIN_SPREAD: write_msg_log('counter %s r_px %s' % (counter, r_px)) return 100 return self.Market_Maker_Price(counter + 1) + 0.1 return r_px def CalcMaxLoss(self, qty): counter = 0 tot = 0 while 1: bid = self.Market_Maker_Price(counter + 0.5) ask = self.Market_Maker_Price(counter - 0.5) if abs(bid - ask) < MIN_SPREAD or bid < self.min_value + MIN_SPREAD \ or ask > self.max_value - MIN_SPREAD: break tot += bid*qty*0.1 print '%7.1f %9.0f %5.2f' % (bid*qty*0.1, tot, bid) counter += 1 return tot def CalcSpent(self): counter = 0 if self.counter > 0: dir = 1 else: dir = -1 tot = 0 qty = self.quantity while abs(counter) < abs(self.counter): px = self.Market_Maker_Price(counter + dir*0.5) tot += px*qty*0.1 print '%7.1f %9.0f %5.2f' % (px*qty*0.1, tot, px) counter += dir return tot def Restore(self, order_dict, last_bid, partial_exec): found_orders = 0 bid_px = None ask_px = None for (key, order1) in order_dict.items(): if order1.ContractID() == self.contract_id: found_orders += 1 if order1.Is_Buy(): bid_px = float(order1.Price()) - 0.00001 else: ask_px = float(order1.Price()) + 0.00001 if found_orders == 2: if bid_px < self.Market_Maker_Price(self.counter): dir = 1 else: dir = -1 while not (bid_px < self.Market_Maker_Price(self.counter) < ask_px): self.counter += dir write_msg_log('Restore counter set to %s for %s' \ % (self.counter, self.contract_id)) self.has_created_orders = 1 self.counter_restored = 1 elif last_bid.has_key(self.contract_id): write_msg_log('restore %s from %s' % (self.contract_id, float(last_bid[self.contract_id]))) self.RestoreFrom1Price(float(last_bid[self.contract_id]), True) if not self.has_created_orders: try: self.partial_exec = partial_exec[self.contract_id] except KeyError: pass def RestoreFromTrades(self, trade_list): last_trade = trade_list[0] for trade1 in trade_list: if trade1.executionTime() > last_trade.executionTime(): last_trade = trade1 # what about partial executions???? self.RestoreFrom1Price(float(last_trade.price), last_trade.Is_Buy()) def RestoreFrom1Price(self, px, is_bid): bid_incr = 0.99*is_bid ask_incr = 0.99*(not is_bid) if self.Market_Maker_Price(self.counter + bid_incr) < px < self.Market_Maker_Price(self.counter - ask_incr): dir = 0 elif px < self.Market_Maker_Price(self.counter): dir = 1 else: dir = -1 while not (self.Market_Maker_Price(self.counter + bid_incr) - 0.00001 < px < self.Market_Maker_Price(self.counter - ask_incr) + 0.00001): if self.Market_Maker_Price(self.counter + bid_incr) < MIN_SPREAD \ or self.Market_Maker_Price(self.counter - ask_incr) > 100-MIN_SPREAD: break self.counter += dir #print self.Market_Maker_Price(self.counter + bid_incr), px, self.Market_Maker_Price(self.counter - ask_incr), 'is_bid', is_bid, 'dir', dir, bid_incr, self.counter #if is_bid == (dir > 0): # self.counter += 1 self.counter_restored = 1 write_msg_log('Restore counter set to %s for %s' \ % (self.counter, self.contract_id)) def alarmHandler(*args): # signal handler for SIGALRM, just raise an exception raise IOError("TimeOut") LOGIN_PERIOD = 1000*60*60*4 # 4 hours expressed in milliseconds tags_with_lists = { 'order' : 1, 'ordID' : 1, 'trade' : 1, 'msg' : 1, 'position' : 1, } class IntradeInterface: def __init__(self, option_dict, contract_dict, secondary = 0): if secondary: # creating trades for test purposes self.user_id = option_dict['user2'] self.password = option_dict['password2'] else: self.user_id = option_dict['user'] self.password = option_dict['password'] self.username = None self.session = None self.next_login_t = None self.last_getx_time = 1 self.order_dict = {} self.pos_dict = {} if option_dict.has_key('dummy'): return try: server_name = option_dict['server'] except KeyError: handle_error('no server specified') if server_name == 'play': method = 'http' self.login_url = 'https://api.intrade.com/aav2/intersite/intersiteLoginXML.jsp?username=%s&password=%s' \ % (self.user_id, self.password) #self.login_url = ('https://api.tradesports.com/aav2/intersite/intersiteLoginXML.jsp', # urllib.urlencode([('username', self.user_id), # ('password', self.password)])) else: method = 'https' self.login_url = None self.server_url = '%s://%s.intrade.com/xml/handler.jsp' \ % (method, server_name) self.getLogin() self.last_order_id = 0 self.got_msg = {} if option_dict.has_key('checkbal'): return if not secondary: self.RestoreOld(contract_dict) def RestoreOld(self, contract_dict): self.GetOrders() self.GetPositions(contract_dict) (last_bid, partial_exec) = self.RestoreOrders() if self.order_dict or self.pos_dict or last_bid: for (contract_id, amm) in contract_dict.items(): amm.Restore(self.order_dict, last_bid, partial_exec) if not amm.Has_Orders() and not amm.Has_Restored_Counter(): trade_list = self.getTradesForContract(contract_id) if trade_list: amm.RestoreFromTrades(trade_list) else: write_msg_log("nothing to restore for %s" % contract_id) def __del__(self): if self.user_id == 'amm' and self.login_url is not None: req = '%s' \ % self.session xml_reply = self.getResponse(req) def start_element(self, name, attrs): name = str(name) # convert from UTF-8 to ascii self.last_name = None if tags_with_lists.has_key(name): if not self.resp_dict.has_key(name): self.resp_dict[name] = [] self.resp_dict[name].append({}) if self.depth == 0: self.current_dict = self.resp_dict[name][-1] else: self.last_name = name self.depth += 1 else: self.last_name = name for (key, val) in attrs.items(): self.current_dict[str(key)] = str(val) def end_element(self, name): #assert name == self.path[-1].name #self.path.pop() if tags_with_lists.has_key(str(name)): self.depth -= 1 if self.depth == 0: self.current_dict = self.resp_dict def char_data(self, data): s = string.strip(str(data)) if s: #print self.current_dict, self.last_name, s self.current_dict[self.last_name] = s def getResponse(self, xml_request, special_url = None, depth = 0): url = special_url or self.server_url signal.signal(signal.SIGALRM, alarmHandler) try: signal.alarm(120) url_fd = urllib.urlopen(url, xml_request) xml_reply = url_fd.read() url_fd.close() except (IOError, socket.sslerror, AttributeError), msg: sleep_time = 5 if depth * sleep_time > 3*60*60: handle_error("IOError %s" % msg) time.sleep(sleep_time) return self.getResponse(xml_request, special_url, depth = depth + 1) signal.alarm(0) self.resp_dict = {} self.current_dict = self.resp_dict self.depth = 0 xmlparser = xml.parsers.expat.ParserCreate() xmlparser.StartElementHandler = self.start_element xmlparser.EndElementHandler = self.end_element xmlparser.CharacterDataHandler = self.char_data try: xmlparser.Parse(xml_reply, True) except xml.parsers.expat.ExpatError: write_msg_log('xml.parsers.expat.ExpatError to op %s' % xml_request) write_msg_log(xml_reply) sleep_time = 2 if depth * sleep_time > 3*60*60: handle_error("IOError %s" % msg) time.sleep(sleep_time) return self.getResponse(xml_request, special_url, depth = depth + 1) if not (self.resp_dict['requestOp'] == 'getUserMessages' and self.resp_dict['resultCode'] == '-1'): write_msg_log('xml_reply raw %s' % xml_reply) elif 0: write_msg_log('getUserMessages %s' % self.resp_dict['timestamp']) return self.resp_dict # Description: Use to login to get valid sessionData and username. # sessionData element is valid for 5hrs or until endOfDay (2am EST approx) def getLogin(self): login_req = '%s%s' \ % (self.user_id, self.password) write_msg_log('login_req %s %s' % (login_req, self.login_url)) while 1: xml_reply = self.getResponse(login_req, special_url = self.login_url) write_msg_log('reply %s' % xml_reply) if xml_reply['resultCode'] != '0' or (xml_reply.has_key('faildesc') and xml_reply['faildesc'] != 'Ok'): write_msg_log('retry login') time.sleep(10.0) #handle_error(str(xml_reply)) else: break self.session = xml_reply['sessionData'] self.next_login_t = long(xml_reply['timestamp']) + LOGIN_PERIOD self.username = xml_reply['username'] def GetExecutions(self): # Use last_getx_time - 1 because there's a slight chance that Intrade # generated a message with the last timestamp after sending the last # getUserMessages response. req = '%s%s' \ % (long(self.last_getx_time) - 1, self.session) xml_reply = self.getResponse(req) if long(xml_reply['timestamp']) > self.next_login_t: self.getLogin() execs = [] if not xml_reply.has_key('msg'): return execs old_last_getx_time = self.last_getx_time for msg1 in xml_reply['msg']: if not msg1: continue try: msg_type = msg1['type'] except KeyError: write_msg_log(msg1) continue msg_id = msg1['msgID'] if self.got_msg.has_key(msg_id): continue self.got_msg[msg_id] = 1 self.last_getx_time = msg1['timestamp'] if msg_type == 'T': o_id = msg1['msg'] if msg1['readFlag'] == 'true': write_msg_log('skip trade already read? %s' % msg1) continue x = OrderExecution(o_id, msg1['quantity'], msg1['conID'], msg1['side'], msg1['price'], msg_id, msg1['timestamp'], # executionTime?? self.order_dict) execs.append(x) elif msg_type in ('D', 'J', 'R', 'S'): handle_error('Problem with a trade: %s' % msg1) else: write_msg_log('msg: %s' % msg1) # if no new messages, increase timestamp to avoid repeating last msg: if self.last_getx_time <= old_last_getx_time: self.last_getx_time = old_last_getx_time + 1 return execs def getTradesForContract(self, contract_id): req = '%s%s' \ % (contract_id, self.session) xml_reply = self.getResponse(req) execs = [] if not xml_reply.has_key('trade'): return execs for trade1 in xml_reply['trade']: x = OrderExecution(trade1['orderID'], trade1['quantity'], trade1['conID'], trade1['side'], trade1['price'], '', trade1['executionTime'], self.order_dict) execs.append(x) return execs def updateMultiOrder(self, orders_to_place): req = ('' \ + 'GTC' \ + '%s' \ + '%s' \ + 'true' \ + 'true') \ % (self.username, self.session) new_order_dict = {} for order in orders_to_place: if order.Is_Buy(): buy_sell = "B" else: buy_sell = "S" req += '' \ % (order.ContractID(), order.Price(), order.quantity, buy_sell) px_str = order.Price() if not ('.' in px_str): px_str += '.0' new_order_dict[(order.ContractID(), px_str)] = order req += '' write_msg_log('new_order_dict %s' % new_order_dict.keys()) xml_reply = self.getResponse(req) try: order_list = xml_reply['order'] except KeyError: handle_error('updateMultiOrder failed ' + str(xml_reply)) for order in order_list: key = (order['conID'], order['limitprice']) try: order0 = new_order_dict[key] except KeyError: handle_error("updateMultiOrder KeyError %s %s" % (key, order)) if order['success'] != 'true': try: why = order['failreason'] except KeyError: why = 'no failreason' handle_error("order failed %s %s %s" % (why, order0, order)) order_id = order['orderID'] order0.SetID(order_id) self.order_dict[order_id] = order0 # GetOrders and GetPositions are used to reinitialize the market # maker status if the program is restarted # def GetOrders(self): req = '%s' \ % self.session xml_reply = self.getResponse(req) if not xml_reply.has_key('order'): return write_msg_log(xml_reply) for order in xml_reply['order']: is_buy = order['side'] == 'B' order0 = Order(is_buy, order['quantity'], order['limitprice'], order['conID']) order0.SetID(order['orderID']) self.order_dict[order['orderID']] = order0 def RestoreOrders(self): last_bid = {} partial_exec = {} try: fd = open(trade_log_file_name, 'r') except IOError: return (last_bid, partial_exec) for line in fd.readlines(): tokens = re.split(' ', line) try: bid = string.strip(tokens[6]) contract_id = tokens[4] except IndexError: continue qty = int(tokens[3]) if tokens[2] == 'B': buy_qty = qty sell_qty = 0 else: buy_qty = 0 sell_qty = qty if bid == 'None': if partial_exec.has_key(contract_id): partial_exec[contract_id][0] += buy_qty partial_exec[contract_id][1] += sell_qty else: partial_exec[contract_id] = [buy_qty, sell_qty] else: last_bid[contract_id] = bid if partial_exec.has_key(contract_id): partial_exec[contract_id][tokens[2] != 'B'] = 0 return (last_bid, partial_exec) def GetPositions(self, contract_dict): req = '%s' \ % self.session xml_reply = self.getResponse(req) if not xml_reply.has_key('position'): return for pos1 in xml_reply['position']: contract_id = pos1['conID'] quantity = pos1['quantity'] try: amm = contract_dict[contract_id] except KeyError: write_msg_log('getPositions unknown contract id %s' % pos1) continue self.pos_dict[contract_id] = quantity #?? #{'totalCost': '0.0', 'bidQty': '10', 'offerQty': '-10', 'openIM': '0.0', 'trueTotalCost': '0.0', 'totalIM': '0.0', 'offerAmt': '-99.0', 'conID': '19', 'netPL': '193.0', 'bidAmt': '1.0', 'quantity': '0'} def GetBalance(self): req = '%s' \ % self.session xml_reply = self.getResponse(req) if not xml_reply.has_key('ccy') or xml_reply['ccy'] != 'USD': raise IOError, xml_reply try: tot = float(xml_reply['available']) + float(xml_reply['frozen']) except KeyError: raise IOError, xml_reply return tot class DummyExchange(IntradeInterface): def __init__(self, option_dict, contract_dict): IntradeInterface.__init__(self, option_dict, contract_dict) self.last_order_num = 10 self.accept_bids_only = option_dict.has_key('bids') def getResponse(self, xml_request): raise NotImplementedError def GetExecutions(self): execs = [] okeys = self.order_dict.keys() if not okeys: return okeys.sort() for i in range(len(okeys)): order = self.order_dict[okeys[i]] if order.Remain_Qty() > 0 \ and (not self.accept_bids_only or order.Is_Buy()): break else: handle_error('no unfilled orders') msg_id = "Msg%d" % self.last_order_num x = OrderExecution(order.ID(), order.quantity, order.ContractID(), ('S', 'B')[order.Is_Buy()], order.Price(), msg_id, str(time.time() * 1000), self.order_dict) write_msg_log('Trade: %s' % x) execs.append(x) return execs def updateMultiOrder(self, orders_to_place): for order0 in orders_to_place: order_id = str(self.last_order_num) order0.SetID(order_id) self.order_dict[order_id] = order0 self.last_order_num += 1 write_msg_log('updateMultiOrder order ids %s' % str(orders_to_place)) if self.last_order_num > 20: print 'placed enough orders, quitting now', self.last_order_num sys.exit(0) # # MarketMakerHandler makes markets in multiple contracts # class MarketMakerHandler: def __init__(self, contract_id_list, option_dict): self.contract_dict = {} orders_to_place = [] for contract_id in contract_id_list: amm = ContractAMM(contract_id) self.contract_dict[contract_id] = amm if option_dict.has_key('dummy'): self.exchange = DummyExchange(option_dict, self.contract_dict) else: self.exchange = IntradeInterface(option_dict, self.contract_dict) for contract_id in contract_id_list: amm = self.contract_dict[contract_id] if not amm.Has_Orders(): #if contract_id == '219617': # amm.counter = 44 # write_msg_log("WARNING: contract 219617 counter set to 44!!!!!!!") new_orders = amm.updateOrders(None) for order in new_orders: orders_to_place.append(order) if option_dict.has_key('checkbal'): return write_msg_log('MarketMakerHandler.__init__ %s' % orders_to_place) if orders_to_place: self.exchange.updateMultiOrder(orders_to_place) def Run(self): while 1: trade_list = self.exchange.GetExecutions() if trade_list: self.Respond(trade_list) else: time.sleep(1) def Respond(self, trade_list): bid_px = {} new_order_dict = {} for trade in trade_list: if trade.From_Order() is None: write_msg_log('skip bogus trade %s' % trade) continue try: amm = self.contract_dict[trade.Contract()] except KeyError: handle_error('Respond trade bad contract %s' % trade) new_orders = amm.updateOrders(trade) write_msg_log('new_orders %s' % str(new_orders)) if new_orders: #print 'Respond', new_orders new_order_dict[trade.Contract()] = new_orders bid_px[trade.Contract()] = new_orders[0].Price() else: bid_px[trade.Contract()] = 'None' for (contract_id, new_orders) in new_order_dict.items(): self.exchange.updateMultiOrder(new_orders) fd = open(trade_log_file_name, 'a') for trade in trade_list: try: try: fd.write("%s %s %d\n" % (trade, bid_px[trade.Contract()], long(trade.executionTime()))) except (ValueError, TypeError): write_msg_log("error writing trade %s %s" % (trade, trade.executionTime())) except KeyError: pass # skipped bogus trade def Check(self, contract_id_list): tot = self.exchange.GetBalance() expected_loss = 0 for contract_id in contract_id_list: amm = self.contract_dict[contract_id] t = amm.CalcSpent() expected_loss += t print '%s %s %s' % (tot, expected_loss, tot + expected_loss) contract_name_dict = { '142210' : "Adult Talkativeness. Men v Women.", '174323' : "The Google Lunar X Prize to be won on/before 31 December 2012", '219617' : "JAP.TARGET.DEC09.>25%", '565196' : "DEM.PRES-GOVT.DEBT", '565197' : "NONDEM.PRES-GOVT.DEBT", '565198' : "DEM.PRES-TROOPS.IRAQ", '565199' : "NONDEM.PRES-TROOPS.IRAQ", '565200' : "DEM.PRES-OIL.FUTURES", '565201' : "DEM.PRES-T.BONDS", } def cvt_trades(): fd = open(trade_log_file_name, 'r') print '' for line in fd.readlines(): tokens = re.split('\s+', line) if tokens[2] == 'S': buy_sell = 'Sold' else: buy_sell = 'Bought' try: contract_name = contract_name_dict[tokens[4]] except KeyError: contract_name = tokens[4] try: trade_time = time.asctime(time.gmtime(long(tokens[7])/1000)) except (IndexError, ValueError): trade_time = '' print '' \ % (buy_sell, tokens[3], contract_name, tokens[5], trade_time) print '
%s%s%sat%s%s
' if __name__ == "__main__": # server option should be "play" for testing avail_opts = ['user=', 'password=', 'server=', # 'play' or 'www' 'calc_max_loss=', 'dummy', # internal test 'bids', # used only with --dummy 'trade_test', # use another acct to generate trade 'user2=', 'password2=',# for other acct in trade_test 'px2=', # price for trade_test 'side=', # for trade_test: 1=buy, 0=sell 'checkbal', 'cvt_trades', ] (options, args) = getopt.getopt(sys.argv[1:], '', avail_opts) option_dict = {} for opt in options: option_dict[opt[0][2:]] = opt[1] if option_dict.has_key('server') and option_dict['server'] == 'play': contract_id_list = [#'219617', # JAP.TARGET.DEC09.>25% '174323', # The Google Lunar X Prize to be won on/before 31 December 2012 '68364', # Democratic Party Nominee to win Nevadas Electoral College Votes in 2008 Election, play sys #'142210', # Adult Talkativeness. Men v Women., play sys #'65543210', # bogus ] else: contract_id_list = [ '565196', # DEM.PRES-GOVT.DEBT '565197', # NONDEM.PRES-GOVT.DEBT '565198', # DEM.PRES-TROOPS.IRAQ '565199', # NONDEM.PRES-TROOPS.IRAQ '565200', # DEM.PRES-OIL.FUTURES '565201', # DEM.PRES-T.BONDS ] if option_dict.has_key('calc_max_loss'): amm = ContractAMM(contract_id_list[-1]) if 0: amm.RestoreFrom1Price(99.2, True) print 'counter', amm.counter, amm.Market_Maker_Price(amm.counter) sys.exit(1) t = amm.CalcMaxLoss(int(option_dict['calc_max_loss'])) print 'max loss', t sys.exit(0) if option_dict.has_key('checkbal'): handler = MarketMakerHandler(contract_id_list, option_dict) handler.Check(contract_id_list) sys.exit(0) if option_dict.has_key('cvt_trades'): cvt_trades() sys.exit(0) cmd = 'ps uxw | grep %s' % sys.argv[0] (status, text) = commands.getstatusoutput(cmd) if status != 0 and not option_dict.has_key('dummy') and option_dict['server'] != 'play': print status, text handle_error(cmd + ' %s ' % status + text) if option_dict.has_key('server') and option_dict['server'] == 'play': trade_log_file_name = 'amm_trade.play.log' msg_log_file_name = 'amm_msg.play.log' handler = MarketMakerHandler(contract_id_list, option_dict) if option_dict.has_key('trade_test'): #trade_list = handler.exchange.GetExecutions() is_buy = int(option_dict['side']) order2 = Order(is_buy, 1, option_dict['px2'], contract_id_list[0]) exchange2 = IntradeInterface(option_dict, {}, secondary = 1) exchange2.updateMultiOrder([order2]) handler.Run()