Cet article poursuit la discussion des backtesters basés sur des événements en Python. Dans l'article précédent, nous avons considéré une hiérarchie de classe de portefeuille qui gérait les positions actuelles, générait des ordres de négociation et suivait les profits et pertes (PnL).
Dans cet article, nous étudierons l'exécution de ces ordres, en créant une hiérarchie de classe qui représentera un mécanisme de traitement des ordres simulé et finalement lié à un courtage ou à d'autres moyens de connectivité du marché.
L'ExecutionHandler décrit ici est extrêmement simple, car il remplit tous les ordres au prix du marché actuel.
Comme pour les précédentes hiérarchies de classes de base abstraites, nous devons importer les propriétés et les décorateurs nécessaires de la bibliothèque abc.
# execution.py
import datetime
import Queue
de l'abc à l'import ABCMeta, méthode abstraite
depuis l'importation d'événement FillEvent, OrderEvent L'ExecutionHandler est similaire aux classes de base abstraites précédentes et a simplement une méthode virtuelle pure, execute_order:
# execution.py
class ExecutionHandler(object):
"""
The ExecutionHandler abstract class handles the interaction
between a set of order objects generated by a Portfolio and
the ultimate set of Fill objects that actually occur in the
market.
The handlers can be used to subclass simulated brokerages
or live brokerages, with identical interfaces. This allows
strategies to be backtested in a very similar manner to the
live trading engine.
"""
__metaclass__ = ABCMeta
@abstractmethod
def execute_order(self, event):
"""
Takes an Order event and executes it, producing
a Fill event that gets placed onto the Events queue.
Parameters:
event - Contains an Event object with order information.
"""
raise NotImplementedError("Should implement execute_order()")
Pour tester les stratégies en arrière-plan, nous devons simuler comment une transaction sera effectuée. La mise en œuvre la plus simple possible est de supposer que tous les ordres sont remplis au prix du marché actuel pour toutes les quantités.
Notez que le FillEvent est donné une valeur de None pour le fill_cost (voir la ligne avant-dernière dans execute_order) car nous avons déjà pris soin du coût de remplissage de l'objet NaivePortfolio décrit dans l'article précédent.
Dans un environnement d'exécution en direct, cette dépendance du lieu serait beaucoup plus importante:
# execution.py
class SimulatedExecutionHandler(ExecutionHandler):
"""
The simulated execution handler simply converts all order
objects into their equivalent fill objects automatically
without latency, slippage or fill-ratio issues.
This allows a straightforward "first go" test of any strategy,
before implementation with a more sophisticated execution
handler.
"""
def __init__(self, events):
"""
Initialises the handler, setting the event queues
up internally.
Parameters:
events - The Queue of Event objects.
"""
self.events = events
def execute_order(self, event):
"""
Simply converts Order objects into Fill objects naively,
i.e. without any latency, slippage or fill ratio problems.
Parameters:
event - Contains an Event object with order information.
"""
if event.type == 'ORDER':
fill_event = FillEvent(datetime.datetime.utcnow(), event.symbol,
'ARCA', event.quantity, event.direction, None)
self.events.put(fill_event)
Cela conclut les hiérarchies de classes nécessaires pour produire un backtester axé sur les événements.