Evaluating what the value of time is

As we saw in the previous parts of this chapter, backtester accuracy is critical when we build a trading strategy. The two main components creating discrepancies between the paper trading of your trading strategy and the actual performance are as follows:

  • The market behavior that we face when the trading strategy goes live
  • The trading system that you use to trade

We saw that the market impact can be medicated by making assumptions regarding the manner in which the market will respond. This part is very challenging because it is just based on assumptions. As regards the second cause of discrepancies, the trading system itself, we can find an easy solution. We will be able to use the trading system as it is to be the backtester. We will get all the main trading components together and we will have them communicate between one another as if they were in production.

When we use the time in production, we can get the time from the computer's clock. For instance, we can stamp a book event coming to the trading strategy by just getting the time from the function now coming from the datetime module in Python. By way of another example, suppose we place an order. Because it is unsure whether the market will respond to this order, we will use a timeout system. This timeout system will call a function after a given period of time if no acknowledgement has been received by the trading system from the market. To accomplish this operation, we usually spawn a thread counting the number of seconds up to the timeout time. When counting, if the state of the order has not changed to acknowledge the order, this thread will call a callback function, onTimeOut. This callback will have the role of handling what should occur when an order timed out on the market. If we want to mock the timeout system in the backtester, this is going to be more challenging. Because we cannot use the real-time clock of the machine to count to the timeout time, we will need to use a simulated clock during the whole process.

The following diagram shows how the backtester will work with the new simulated clock component handling the time. Each time a component needs to get the time, it will call a function, getTime. This function will return the simulated time (being the time of the last tick read by the LiquidityProvider class):

  1. We will implement the Simulated Clock function (SimulatedRealClock class). Each time the trading system is started in backtest mode, we will use the SimulatedRealClock class with the simulated=True argument. If the trading system runs in real time to place orders on the market, the SimulatedRealClock class will be created without arguments or with the simulated=False argument, . When the time is given by a simulated time, the time will come from the order timestamps:
from datetime import datetime

class SimulatedRealClock:
def __init__(self,simulated=False):
self.simulated = simulated
self.simulated_time = None
def process_order(self,order):
self.simulated_time=
datetime.strptime(order['timestamp'], '%Y-%m-%d %H:%M:%S.%f')
def getTime(self):
if not self.simulated:
return datetime.now()
else:
return self.simulated_time

realtime=SimulatedRealClock()
print(realtime.getTime())
# It will return the date/time when you run this code
simulatedtime=SimulatedRealClock(simulated=True)
simulatedtime.process_order({'id' : 1, 'timestamp' : '2018-06-29 08:15:27.243860'})
print(simulatedtime.getTime())
# It will return 2018-06-29 08:15:27.243860

When coding a trading system, when you need the value of time, you will always need to use a reference to the SimulatedRealClock class and use the value returned by the getTime function.

  1. In the following code, we will see the implementation of an order management system timing out 5 seconds after sending an order. We will first show you how to create a TimeOut class counting to the timeout value and calling a function when a timeout occurs. This TimeOut class is a thread. It means that the execution of this class will be concurrent to the main program. The arguments to build this class are the SimulateRealClock class, the time considered as the timeout time, and a function that will be called as a callback, fun. This class will run a loop as long as the current time is not older than the time to stop the countdown. If the time is higher and the TimeOut class has not been disabled, the callback function will be called. If the TimeOut class is disabled because the response to the order arrived in the system, the callback function will not be called. We can observe that we will compare the time to stop the timer with the current time by using the getTime function from the SimulatedRealClock class:
class TimeOut(threading.Thread):
def __init__(self,sim_real_clock,time_to_stop,fun):
super().__init__()
self.time_to_stop=time_to_stop
self.sim_real_clock=sim_real_clock
self.callback=fun
self.disabled=False
def run(self):
while not self.disabled and
self.sim_real_clock.getTime() < self.time_to_stop:
sleep(1)
if not self.disabled:
self.callback()
  1. The following OMS class that we will implement is just a small subset of what the order manager service can do. This OMS class will be in charge of sending an order. Each time an order is sent, a 5-second timeout will be created. This means that the onTimeOut function will be called if the OMS does not receive a response to the order placed on the market. We can observe that we build the TimeOut class by using the getTime function from the SimulatedRealClock class:
class OMS:
def __init__(self,sim_real_clock):
self.sim_real_clock = sim_real_clock
self.five_sec_order_time_out_management=
TimeOut(sim_real_clock,
sim_real_clock.getTime()+timedelta(0,5),
self.onTimeOut)
def send_order(self):
self.five_sec_order_time_out_management.disabled = False
self.five_sec_order_time_out_management.start()
print('send order')
def receive_market_reponse(self):
self.five_sec_order_time_out_management.disabled = True
def onTimeOut(self):
print('Order Timeout Please Take Action')

When we run the following code to verify whether that works, we create two cases:

  • Case 1: This will use the OMS in real time by using SimulatedRealClock in real-time mode.
  • Case 2: This will use the OMS in simulated mode by using SimulatedRealClock in simulated mode.
  1. In the following code, Case 1 will trigger a timeout after 5 seconds, and Case 2 will trigger a timeout when the simulated time is older than the time to trig the timeout:
if __name__ == '__main__':
print('case 1: real time')
simulated_real_clock=SimulatedRealClock()
oms=OMS(simulated_real_clock)
oms.send_order()
for i in range(10):
print('do something else: %d' % (i))
sleep(1)

print('case 2: simulated time')
simulated_real_clock=SimulatedRealClock(simulated=True)
simulated_real_clock.
process_order({'id' : 1,
'timestamp' : '2018-06-29 08:15:27.243860'})
oms = OMS(simulated_real_clock)
oms.send_order()
simulated_real_clock.
process_order({'id': 1,
'timestamp': '2018-06-29 08:21:27.243860'})

When we use a backtester as a trading system, it is very important to use a class capable of handling simulation and real time. You will be able to achieve better accuracy by using the trading system and you will build better confidence in your trading strategy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.215.183.194