Created
September 19, 2015 13:55
-
-
Save audubon/e5a35b24145993c544c0 to your computer and use it in GitHub Desktop.
simexchange
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 '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() | |
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:14 | |
,MessageKey.SYMBOL:'CLZ15' | |
,MessageKey.SIDE : Side.SELL | |
,MessageKey.PRICE: 23.33 | |
,MessageKey.ORDERID: orderId.next() }} | |
ob.addOrder(msg) | |
ob.displaybook() | |
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() | |
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() | |
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() | |
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() | |
""" | |
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() | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
great http://audubontechnology.appspot.com/