Example #1
0
	def create_order_schedule(self,lob=None,spread=5,delta=1,time=0):
		
		qty_density=self.qty_density
		depth=self.depth
		
		try:
			best_bid=lob['bids']['best']
		except KeyError:
			best_bid=1+depth
		
		try:
			best_ask=lob['asks']['best']
		except KeyError:
			best_ask=200-depth
		
		
		if self.inventory!=0:
			if self.inventory<0:
			
					order_type='Bid'
					spread_mult=-1
			elif self.inventory>0:
					order_type='Ask'
					spread_mult=1
			
			df=pd.DataFrame(list(self.trade_manager.fifo)).groupby('price').count()
			
			for row in df.iterrows():
				price=row[0]
				quantity=row[1][0]
				order=Order(self.tid,order_type,price+spread_mult*spread,quantity,time,oid=self.make_oid(time))
				
				self.add_order(order,verbose=False)
			
			
			# if abs(self.inventory)<self.depth:
				# #need to supplement bids or offers to get to requisite quote depth
				# too_add=self.depth-abs(self.inventory)
				# while too_add>0:
					# price=price+spread_mult
					# quantity=1
					# order=Order(self.tid,order_type,price,quantity,time,oid=self.make_oid(time))
					# too_add-=1

			if self.inventory<0:
				order_type='Ask'
				best_ask=max(best_ask,max(df.index.values))
				
				for price in range(best_ask,best_ask+depth):
					order=Order(self.tid,'Ask',price,qty_density,time,oid=self.make_oid(time))
					self.add_order(order,verbose=False)
				
			else:
				#work out the bids
				order_type='Bid'
				best_bid=min(best_bid,min(df.index.values))
				
				for price in range(best_bid-depth,best_bid):
					order=Order(self.tid,'Bid',price,qty_density,time,oid=self.make_oid(time))
					self.add_order(order,verbose=False)
		else:
			#no inventory, issue bids and offers around best bid and ask
			
			for price in range(best_ask,best_ask+depth):
					order=Order(self.tid,'Ask',price,qty_density,time,oid=self.make_oid(time))
					self.add_order(order,verbose=False)
				
			
				#work out the bids
			for price in range(best_bid-depth,best_bid):
					order=Order(self.tid,'Bid',price,qty_density,time,oid=self.make_oid(time))
					self.add_order(order,verbose=False)
				
		return self.orders_dic.copy() #to stop subsequent mutation
Example #2
0
    def get_order(self, tape=None):
        inventory = self.inventory
        buy_order = None
        sell_order = None
        rmean = self.estimates[self.time]

        bid_possible = inventory < self.qty_max
        ask_possible = inventory > self.qty_min

        buy_surplus = 0
        sell_surplus = 0

        if bid_possible:
            buy_pref = self.preference[inventory + 1]
            buy_valuation = rmean + buy_pref
            buy_price = np.random.randint(rmean - self.rmax + buy_pref,
                                          rmean - self.rmin + buy_pref)

            buy_price = self.price_or_best_price(
                buy_price, 'Bid')  #choose price no better than best
            buy_surplus = buy_valuation - buy_price

        if ask_possible:
            sell_pref = self.preference[inventory]
            sell_valuation = rmean + sell_pref
            sell_price = np.random.randint(rmean + self.rmin + sell_pref,
                                           rmean + self.rmax + sell_pref)
            sell_price = self.price_or_best_price(
                sell_price, 'Ask')  #choose price no better than best
            sell_surplus = sell_price - sell_valuation

        if self.market_make:
            #market maker formulation - submit bid and ask where possible
            if bid_possible and buy_surplus > 0:
                buy_order = Order(tid=self.tid,
                                  otype='Bid',
                                  price=buy_price,
                                  qty=1,
                                  time=self.time,
                                  oid=self.get_oid())
                #record internally
                self.add_order(buy_order)
            if ask_possible and sell_surplus > 0:
                sell_order = Order(tid=self.tid,
                                   otype='Ask',
                                   price=sell_price,
                                   qty=1,
                                   time=self.time,
                                   oid=self.get_oid())
                #record internally
                self.add_order(sell_order)

        else:
            #single order formulation
            if bid_possible and buy_surplus > 0 and buy_surplus >= sell_surplus:
                buy_order = Order(tid=self.tid,
                                  otype='Bid',
                                  price=buy_price,
                                  qty=1,
                                  time=self.time,
                                  oid=self.get_oid())
                #record internally
                self.add_order(buy_order)

            elif ask_possible and sell_surplus > 0:
                sell_order = Order(tid=self.tid,
                                   otype='Ask',
                                   price=sell_price,
                                   qty=1,
                                   time=self.time,
                                   oid=self.get_oid())
                #record internally
                self.add_order(sell_order)

        return buy_order, sell_order
Example #3
0
def customer_orders(time,
                    last_update,
                    traders,
                    n_buyers,
                    n_sellers,
                    os,
                    pending,
                    verbose,
                    quantity=None,
                    oid=-1):
    #oid=-1 number we start at for unique oid codes. Will increase negatively (to quickly differentiate from qid)

    def sysmin_check(price):
        if price < bse_sys_minprice:
            print('WARNING: price < bse_sys_min -- clipped')
            price = bse_sys_minprice
        return price

    def sysmax_check(price):
        if price > bse_sys_maxprice:
            print('WARNING: price > bse_sys_max -- clipped')
            price = bse_sys_maxprice
        return price

    def getorderprice(i, sched, n, mode, issuetime):
        # does the first schedule range include optional dynamic offset function(s)?
        if len(sched[0]) > 2:
            offsetfn = sched[0][2]
            if callable(offsetfn):
                # same offset for min and max
                offset_min = offsetfn(issuetime)
                offset_max = offset_min
            else:
                sys.exit(
                    'FAIL: 3rd argument of sched in getorderprice() not callable'
                )
            if len(sched[0]) > 3:
                # if second offset function is specfied, that applies only to the max value
                offsetfn = sched[0][3]
                if callable(offsetfn):
                    # this function applies to max
                    offset_max = offsetfn(issuetime)
                else:
                    sys.exit(
                        'FAIL: 4th argument of sched in getorderprice() not callable'
                    )
        else:
            offset_min = 0.0
            offset_max = 0.0

        pmin = sysmin_check(offset_min + min(sched[0][0], sched[0][1]))
        pmax = sysmax_check(offset_max + max(sched[0][0], sched[0][1]))
        prange = pmax - pmin
        stepsize = prange / (n - 1)
        halfstep = round(stepsize / 2.0)

        if mode == 'fixed':
            orderprice = pmin + int(i * stepsize)
        elif mode == 'jittered':
            orderprice = pmin + int(i * stepsize) + random.randint(
                -halfstep, halfstep)
        elif mode == 'random':
            if len(sched) > 1:
                # more than one schedule: choose one equiprobably
                s = random.randint(0, len(sched) - 1)
                pmin = sysmin_check(min(sched[s][0], sched[s][1]))
                pmax = sysmax_check(max(sched[s][0], sched[s][1]))
            orderprice = random.randint(pmin, pmax)
        else:
            sys.exit('FAIL: Unknown mode in schedule')
        orderprice = sysmin_check(sysmax_check(orderprice))
        return orderprice

    def getissuetimes(n_traders, mode, interval, shuffle, fittointerval):
        interval = float(interval)
        if n_traders < 1:
            sys.exit('FAIL: n_traders < 1 in getissuetime()')
        elif n_traders == 1:
            tstep = interval
        else:
            tstep = interval / (n_traders - 1)
        arrtime = 0
        issuetimes = []
        for t in range(n_traders):
            if mode == 'periodic':
                arrtime = interval
            elif mode == 'drip-fixed':
                arrtime = t * tstep
            elif mode == 'drip-jitter':
                arrtime = t * tstep + tstep * random.random()
            elif mode == 'drip-poisson':
                # poisson requires a bit of extra work
                interarrivaltime = random.expovariate(n_traders / interval)
                arrtime += interarrivaltime
            else:
                sys.exit('FAIL: unknown time-mode in getissuetimes()')
            issuetimes.append(arrtime)

        # at this point, arrtime is the last arrival time
        if fittointerval and ((arrtime > interval) or (arrtime < interval)):
            # generated sum of interarrival times longer than the interval
            # squish them back so that last arrival falls at t=interval
            for t in range(n_traders):
                issuetimes[t] = interval * (issuetimes[t] / arrtime)
        # optionally randomly shuffle the times
        if shuffle:
            for t in range(n_traders):
                i = (n_traders - 1) - t
                j = random.randint(0, i)
                tmp = issuetimes[i]
                issuetimes[i] = issuetimes[j]
                issuetimes[j] = tmp
        return issuetimes

    def getschedmode(time, os):
        got_one = False
        for sched in os:
            if (sched['from'] <= time) and (time < sched['to']):
                # within the timezone for this schedule
                schedrange = sched['ranges']
                mode = sched['stepmode']
                got_one = True
                break  # jump out the loop -- so the first matching timezone has priority over any others
        if not got_one:
            sys.exit('Fail: time=%5.2f not within any timezone in os=%s' %
                     (time, os))
        return (schedrange, mode)

    #n_buyers = trader_stats['n_buyers']
    #n_sellers = trader_stats['n_sellers']

    shuffle_times = True

    cancellations = []
    dispatched_orders = []

    if len(pending) < 1:
        # list of pending (to-be-issued) customer orders is empty, so generate a new one
        new_pending = []

        # demand side (buyers)
        issuetimes = getissuetimes(n_buyers, os['timemode'], os['interval'],
                                   shuffle_times, True)

        ordertype = 'Bid'
        (sched, mode) = getschedmode(time, os['dem'])
        for t in range(n_buyers):
            issuetime = time + issuetimes[t]
            tname = 'B%02d' % t
            orderprice = getorderprice(t, sched, n_buyers, mode, issuetime)

            order = Order(tname,
                          ordertype,
                          orderprice,
                          quantity(),
                          issuetime,
                          qid=None,
                          oid=oid)
            oid -= 1
            new_pending.append(order)

        # supply side (sellers)
        issuetimes = getissuetimes(n_sellers, os['timemode'], os['interval'],
                                   shuffle_times, True)
        ordertype = 'Ask'
        (sched, mode) = getschedmode(time, os['sup'])
        for t in range(n_sellers):
            issuetime = time + issuetimes[t]
            tname = 'S%02d' % t
            orderprice = getorderprice(t, sched, n_sellers, mode, issuetime)

            order = Order(tname,
                          ordertype,
                          orderprice,
                          quantity(),
                          issuetime,
                          qid=None,
                          oid=oid)
            oid -= 1

            new_pending.append(order)
    else:
        # there are pending future orders: issue any whose timestamp is in the past
        new_pending = []

        for order in pending:
            if order.time < time:
                dispatched_orders.append(order)
                # this order should have been issued by now
                # issue it to the trader
                tname = order.tid
                response = traders[tname].add_order(order, verbose)
                if verbose:
                    print('Customer order: %s %s' % (response[0], order))
                if response[0] == 'LOB_Cancel':
                    assert tname == response[1]['tid']
                    cancellations.append(response[1])
                    if verbose: print('Cancellations: %s' % (cancellations))
                # and then don't add it to new_pending (i.e., delete it)
            else:
                # this order stays on the pending list
                new_pending.append(order)
    return [new_pending, cancellations, dispatched_orders, oid]