Skip to content

Instantly share code, notes, and snippets.

@audubon
Created September 19, 2015 13:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save audubon/e5a35b24145993c544c0 to your computer and use it in GitHub Desktop.
Save audubon/e5a35b24145993c544c0 to your computer and use it in GitHub Desktop.
simexchange
import pykka
import pykka.gevent
import gevent
import numpy as np
import copy,sys, pprint , blist
from collections import defaultdict
import logging
import signal
import pykka.debug
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('pykka')
def IdGenerator():
sid = 0
while True:
sid +=1
yield sid
orderId = IdGenerator()
class orderbook(object):
# XXX wip
def __init__ (self):
self.bids = blist.sorteddict()
self.offers = blist.sorteddict()
def addOrder(self, msg):
order = msg.get(MessageKey.PAYLOAD)
if order.get(MessageKey.SIDE) == Side.BUY:
self.bids.setdefault(order.get(MessageKey.PRICE), []).append(order)
elif order.get(MessageKey.SIDE) == Side.SELL:
self.offers.setdefault(order.get(MessageKey.PRICE), []).append(order)
self.match( order.get(MessageKey.SIDE) )
def match(self,newside):
if len(self.bids) and len(self.offers):
bbkey = self.bids.keys()[len(self.bids.keys())-1]
bokey = self.offers.keys()[0]
bestbid = self.bids[bbkey][0]
bestoffer = self.offers[bokey][0]
if bestbid[MessageKey.PRICE] >= bestoffer[MessageKey.PRICE]:
bbqty = bestbid.get(MessageKey.QTY)
boqty = bestoffer.get(MessageKey.QTY)
#got match
if newside==Side.BUY:
if bbqty < boqty:
bestoffer[MessageKey.QTY] = boqty - bbqty
#trade on offer
del self.bids[bbkey][0]
if len(self.bids[bbkey])==0:
del self.bids[bbkey]
elif bbqty > boqty:
bestbid[MessageKey.QTY] = bbqty - boqty
del self.offers[bokey][0]
if len(self.offers[bokey])==0:
del self.offers[bokey]
self.match(newside)
elif bbqty == boqty:
del self.bids[bbkey][0]
if len(self.bids[bbkey])==0:
del self.bids[bbkey]
del self.offers[bokey][0]
if len(self.offers[bokey])==0:
del self.offers[bokey]
if newside==Side.SELL:
if bbqty > boqty:
bestbid[MessageKey.QTY] = bbqty - boqty
#trade on bid
del self.offers[bokey][0]
if len(self.offers[bokey])==0:
del self.offers[bokey]
elif bbqty < boqty:
bestoffer[MessageKey.QTY] = boqty - bbqty
del self.bids[bbkey][0]
if len(self.bids[bbkey])==0:
del self.bids[bbkey]
self.match(newside)
elif bbqty == boqty:
del self.bids[bbkey][0]
if len(self.bids[bbkey])==0:
del self.bids[bbkey]
del self.offers[bokey][0]
if len(self.offers[bokey])==0:
del self.offers[bokey]
def displaybook(self):
print
print 'BOOK'
for k in reversed(self.offers.keys()):
print k,self.offers[k]
print '-------------------------------------------------------------------------'
for k in reversed(self.bids.keys()):
print k,':',self.bids[k]
def __repr__(self):
return pprint.pformat((self.offers ,"========================================", self.bids))
class position(object):
def __init__ (self):
pass
class portfolio(object):
def __init__ (self):
self.positions = defaultdict(int)
def addExecution(self,execution):
self.positions[execution.get(MessageKey.ORDER).get(MessageKey.SYMBOL)] += execution.get(MessageKey.QTY)
def __repr__ (self):
return repr(self.positions)
class ordermanager(object):
def __init__ (self):
self.orders = dict()
def addOrder(self,order):
self.orders[order.get(MessageKey.ORDERID)] = order
def removeOrder(self,order):
try:
del self.orders[order.get(MessageKey.ORDERID)]
except KeyError,kerr:
print(sys.exc_info()[0])
def __repr__ (self):
return repr(self.orders)
class ExecutionActor(pykka.gevent.GeventActor):
def __init__(self, **kwargs):
super(ExecutionActor, self).__init__()
self.inputs = kwargs.get('inputs')
self.myname = kwargs.get('myname')
def on_receive(self, message):
if message.get(MessageKey.MSGTYPE)==MessageType.ORDER:
logger.info("%s %s"%(self.myname, message.get(MessageKey.PAYLOAD)))
message={MessageKey.MSGTYPE:MessageType.FILL
, MessageKey.PAYLOAD : {MessageKey.QTY : message.get(MessageKey.PAYLOAD).get(MessageKey.QTY)
, MessageKey.PRICE : np.around( message.get(MessageKey.PAYLOAD).get(MessageKey.PRICE) - .02 ,2)
, MessageKey.ORDER : message.get(MessageKey.PAYLOAD) }}
pykka.ActorRegistry.broadcast(message, target_class=PortfolioActor)
else:
None
def on_stop(self):
logger.info("stopping %s"% self.myname)
def on_start(self):
logger.info("starting %s"% self.myname)
class OrderManagerActor(pykka.gevent.GeventActor):
def __init__(self, **kwargs):
super(OrderManagerActor, self).__init__()
self.inputs = kwargs.get('inputs')
self.myname = kwargs.get('myname')
def on_receive(self, message):
pass
def on_stop(self):
logger.info("stopping %s"% self.myname)
def on_start(self):
logger.info("starting %s"% self.myname)
class PortfolioActor(pykka.gevent.GeventActor):
def __init__(self, **kwargs):
super(PortfolioActor, self).__init__()
self.inputs = kwargs.get('inputs')
self.myname = kwargs.get('myname')
self.portfolio = portfolio()
def on_receive(self, message):
if message.get(MessageKey.MSGTYPE)==MessageType.FILL:
logger.info("%s %s"% (self.myname, message.get(MessageKey.PAYLOAD)))
self.portfolio.addExecution(message.get(MessageKey.PAYLOAD))
def on_stop(self):
print self.portfolio
logger.info("stopping %s"% self.myname)
def on_start(self):
logger.info("starting %s"% self.myname)
class DataFeedActor(pykka.gevent.GeventActor):
def __init__(self, **kwargs):
super(DataFeedActor, self).__init__()
self.inputs = kwargs.get('inputs')
self.myname = kwargs.get('myname')
def on_receive(self, message):
print message
def _publish(self):
prices = np.random.normal(size=34).cumsum() + 100
for current in prices:
bmessage={MessageKey.MSGTYPE:MessageType.QUOTE, MessageKey.PAYLOAD : {MessageKey.PRICE:current-.02,MessageKey.QUOTETYPE: QuoteType.BID}}
omessage={MessageKey.MSGTYPE:MessageType.QUOTE, MessageKey.PAYLOAD : {MessageKey.PRICE:current+.02,MessageKey.QUOTETYPE: QuoteType.OFFER}}
pykka.ActorRegistry.broadcast(bmessage, target_class=StrategyActor)
pykka.ActorRegistry.broadcast(omessage, target_class=StrategyActor)
gevent.sleep(0) #yields so other gevents fire
def on_stop(self):
logger.info("stopping %s"% self.myname)
def on_start(self):
logger.info("starting %s"% self.myname)
self._publish()
class StrategyActor(pykka.gevent.GeventActor):
def __init__(self, **kwargs):
super(StrategyActor, self).__init__()
self.inputs = kwargs.get('inputs')
self.myname = kwargs.get('myname')
self.actorRefs = kwargs.get('actorRefs')
self.__prices = []
self.nbbo={QuoteType.BID : None, QuoteType.OFFER : None}
def on_receive(self, message):
if message.get(MessageKey.MSGTYPE)==MessageType.QUOTE:
z= message.get(MessageKey.PAYLOAD).get(MessageKey.PRICE)
bbo= message.get(MessageKey.PAYLOAD).get(MessageKey.QUOTETYPE)
self.nbbo[bbo] = z
if not None in self.nbbo.values():
self.__logic( np.mean(self.nbbo.values()) )
else:
None
def on_stop(self):
logger.info("stopping %s"% self.myname)
def on_start(self):
logger.info("starting %s"% self.myname)
def __logic(self,price):
logger.info("%s %s"%(self.myname, price))
self.__prices.append( price )
if len(self.__prices)>11:
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:np.random.randint(-5,5, size=1)[0]
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.BUY
,MessageKey.PRICE: np.around( np.mean(self.nbbo.values()) - .01 ,2)
,MessageKey.ORDERID: orderId.next() }}
pykka.ActorRegistry.get_by_class(ExecutionActor)[0].tell(msg)
self.__prices.pop(0)
class MessageKey(object):
PAYLOAD = 'payload'
PRICE = 'price'
ORDER = 'order'
QTY = 'qty'
QUOTETYPE = 'quotetype'
SYMBOL = 'symbol'
MSGTYPE = 'msgtype'
SIDE = 'side'
ORDERID = 'oid'
class MessageType(object):
FILL = 1
ORDER = 2
QUOTE = 3
class Side(object):
BUY = 1
SELL = 2
class QuoteType(object):
BID = 1
OFFER = 2
if __name__ == '__main__':
ob=orderbook()
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:23
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.BUY
,MessageKey.PRICE: 23.3
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:12
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.BUY
,MessageKey.PRICE: 23.33
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:14
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.SELL
,MessageKey.PRICE: 23.33
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:12
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.BUY
,MessageKey.PRICE: 23.33
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:3
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.SELL
,MessageKey.PRICE: 23.34
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:2
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.SELL
,MessageKey.PRICE: 23.36
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:4
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.SELL
,MessageKey.PRICE: 23.36
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
msg = { MessageKey.MSGTYPE:MessageType.ORDER
, MessageKey.PAYLOAD : { MessageKey.QTY:3
,MessageKey.SYMBOL:'CLZ15'
,MessageKey.SIDE : Side.BUY
,MessageKey.PRICE: 23.36
,MessageKey.ORDERID: orderId.next() }}
ob.addOrder(msg)
ob.displaybook()
print
"""
ExecutionActorRef = ExecutionActor.start(myname="ExecutionActor")
PortfolioActorRef = PortfolioActor.start(myname="PortfolioActor")
OrderManagerActorRef = OrderManagerActor.start(myname="OrderManagerActor")
StrategyActorRef = StrategyActor.start(inputs="CL",myname="StrategyActor")
DataFeedActorRef = DataFeedActor.start(myname="DataFeedActor")
pykka.ActorRegistry.stop_all()
"""
@audubon
Copy link
Author

audubon commented Sep 19, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment