পূর্ববর্তী নিবন্ধে আমরা ইভেন্ট-চালিত ব্যাকটেস্টারের ধারণাটি বর্ণনা করেছি। এই সিরিজের বাকি নিবন্ধগুলি সামগ্রিক সিস্টেম তৈরি করে এমন পৃথক শ্রেণির শ্রেণিবিন্যাসের প্রতিটিতে মনোনিবেশ করবে। এই নিবন্ধে আমরা ইভেন্টগুলি এবং কীভাবে তাদের অবজেক্টগুলির মধ্যে তথ্য যোগাযোগ করতে ব্যবহার করা যেতে পারে তা বিবেচনা করব।
যেমনটি পূর্ববর্তী নিবন্ধে আলোচনা করা হয়েছে, ট্রেডিং সিস্টেমটি দুটি ওয়েলিং লুপ ব্যবহার করে - একটি বাহ্যিক এবং একটি অভ্যন্তরীণ। অভ্যন্তরীণ ওয়েলিং লুপ একটি ইন-মেমরি সারি থেকে ইভেন্টগুলির ক্যাপচার পরিচালনা করে, যা পরবর্তী ক্রিয়াকলাপের জন্য উপযুক্ত উপাদানটিতে রুট করা হয়। এই অবকাঠামোতে চার ধরণের ইভেন্ট রয়েছেঃ
পিতা ক্লাসটি ইভেন্ট নামে পরিচিত। এটি একটি বেস ক্লাস এবং কোনও কার্যকারিতা বা নির্দিষ্ট ইন্টারফেস সরবরাহ করে না। পরবর্তী বাস্তবায়নগুলিতে ইভেন্ট অবজেক্টগুলি সম্ভবত আরও জটিলতা বিকাশ করবে এবং সুতরাং আমরা একটি শ্রেণি শ্রেণীবদ্ধকরণ তৈরি করে এই জাতীয় সিস্টেমগুলির নকশা ভবিষ্যতের প্রমাণ করছি।
# event.py
class Event(object):
"""
Event is base class providing an interface for all subsequent
(inherited) events, that will trigger further events in the
trading infrastructure.
"""
pass
মার্কেট ইভেন্টটি ইভেন্ট থেকে উত্তরাধিকার সূত্রে প্রাপ্ত এবং এটি একটি
# event.py
class MarketEvent(Event):
"""
Handles the event of receiving a new market update with
corresponding bars.
"""
def __init__(self):
"""
Initialises the MarketEvent.
"""
self.type = 'MARKET'
একটি SignalEvent এর জন্য একটি টিকার প্রতীক, জেনারেট করার জন্য একটি টাইমস্ট্যাম্প এবং একটি নির্দেশ প্রয়োজন যাতে একটি পোর্টফোলিও অবজেক্টকে পরামর্শ দেওয়া যায়।
# event.py
class SignalEvent(Event):
"""
Handles the event of sending a Signal from a Strategy object.
This is received by a Portfolio object and acted upon.
"""
def __init__(self, symbol, datetime, signal_type):
"""
Initialises the SignalEvent.
Parameters:
symbol - The ticker symbol, e.g. 'GOOG'.
datetime - The timestamp at which the signal was generated.
signal_type - 'LONG' or 'SHORT'.
"""
self.type = 'SIGNAL'
self.symbol = symbol
self.datetime = datetime
self.signal_type = signal_type
অর্ডার ইভেন্ট একটি সিগন্যাল ইভেন্টের চেয়ে কিছুটা জটিল কারণ এতে সিগন্যাল ইভেন্টের উপরে উল্লিখিত বৈশিষ্ট্যগুলির পাশাপাশি একটি পরিমাণ ক্ষেত্র রয়েছে। পরিমাণটি পোর্টফোলিও সীমাবদ্ধতার দ্বারা নির্ধারিত হয়। এছাড়াও অর্ডার ইভেন্টের একটি প্রিন্ট_অর্ডার (()) পদ্ধতি রয়েছে, যা প্রয়োজনে কনসোলে তথ্য আউটপুট করতে ব্যবহৃত হয়।
# event.py
class OrderEvent(Event):
"""
Handles the event of sending an Order to an execution system.
The order contains a symbol (e.g. GOOG), a type (market or limit),
quantity and a direction.
"""
def __init__(self, symbol, order_type, quantity, direction):
"""
Initialises the order type, setting whether it is
a Market order ('MKT') or Limit order ('LMT'), has
a quantity (integral) and its direction ('BUY' or
'SELL').
Parameters:
symbol - The instrument to trade.
order_type - 'MKT' or 'LMT' for Market or Limit.
quantity - Non-negative integer for quantity.
direction - 'BUY' or 'SELL' for long or short.
"""
self.type = 'ORDER'
self.symbol = symbol
self.order_type = order_type
self.quantity = quantity
self.direction = direction
def print_order(self):
"""
Outputs the values within the Order.
"""
print "Order: Symbol=%s, Type=%s, Quantity=%s, Direction=%s" % \
(self.symbol, self.order_type, self.quantity, self.direction)
FillEvent হল সবচেয়ে জটিল ইভেন্ট। এটিতে একটি অর্ডার কখন পূরণ করা হয়েছিল তার জন্য একটি টাইমস্ট্যাম্প রয়েছে, অর্ডারের প্রতীক এবং এটি সম্পাদিত বিনিময়, লেনদেনকৃত শেয়ারের পরিমাণ, ক্রয়ের প্রকৃত মূল্য এবং কমিশন।
ইন্টারেক্টিভ ব্রোকারদের কমিশন ব্যবহার করে কমিশন গণনা করা হয়। মার্কিন এপিআই অর্ডারের জন্য এই কমিশনটি প্রতি অর্ডারে ন্যূনতম 1.30 মার্কিন ডলার, বাণিজ্যের আকার 500 ইউনিটের নিচে বা তার বেশি কিনা তার উপর নির্ভর করে 0.013 মার্কিন ডলার বা 0.08 মার্কিন ডলার প্রতি শেয়ারের একক হার সহ।
# event.py
class FillEvent(Event):
"""
Encapsulates the notion of a Filled Order, as returned
from a brokerage. Stores the quantity of an instrument
actually filled and at what price. In addition, stores
the commission of the trade from the brokerage.
"""
def __init__(self, timeindex, symbol, exchange, quantity,
direction, fill_cost, commission=None):
"""
Initialises the FillEvent object. Sets the symbol, exchange,
quantity, direction, cost of fill and an optional
commission.
If commission is not provided, the Fill object will
calculate it based on the trade size and Interactive
Brokers fees.
Parameters:
timeindex - The bar-resolution when the order was filled.
symbol - The instrument which was filled.
exchange - The exchange where the order was filled.
quantity - The filled quantity.
direction - The direction of fill ('BUY' or 'SELL')
fill_cost - The holdings value in dollars.
commission - An optional commission sent from IB.
"""
self.type = 'FILL'
self.timeindex = timeindex
self.symbol = symbol
self.exchange = exchange
self.quantity = quantity
self.direction = direction
self.fill_cost = fill_cost
# Calculate commission
if commission is None:
self.commission = self.calculate_ib_commission()
else:
self.commission = commission
def calculate_ib_commission(self):
"""
Calculates the fees of trading based on an Interactive
Brokers fee structure for API, in USD.
This does not include exchange or ECN fees.
Based on "US API Directed Orders":
https://www.interactivebrokers.com/en/index.php?f=commission&p=stocks2
"""
full_cost = 1.3
if self.quantity <= 500:
full_cost = max(1.3, 0.013 * self.quantity)
else: # Greater than 500
full_cost = max(1.3, 0.008 * self.quantity)
full_cost = min(full_cost, 0.5 / 100.0 * self.quantity * self.fill_cost)
return full_cost
সিরিজের পরবর্তী নিবন্ধে আমরা বিবেচনা করতে যাচ্ছি কিভাবে একই শ্রেণীর ইন্টারফেসের মাধ্যমে ঐতিহাসিক ব্যাকটেস্টিং এবং লাইভ ট্রেডিং উভয়েরই অনুমতি দেয় এমন একটি মার্কেট ডেটাহ্যান্ডলার ক্লাস হাইয়ারারচি বিকাশ করা যায়।