پیتھون کے ساتھ ایونٹ سے چلنے والی بیک ٹیسٹنگ - حصہ VIII

مصنف:نیکی, تخلیق: 2019-03-26 16:38:59, تازہ کاری:

یہ کچھ عرصہ ہو گیا ہے جب سے ہم نے ایونٹ سے چلنے والے بیک ٹیسٹر پر غور کیا ہے ، جس پر ہم نے اس مضمون میں تبادلہ خیال کرنا شروع کیا۔ حصہ VI میں میں نے ایک اسٹینڈ ان ایگزیکشن ہینڈلر ماڈل کوڈ کرنے کا طریقہ بیان کیا ہے جو تاریخی بیک ٹسٹنگ کی صورتحال کے لئے کام کرتا ہے۔ اس مضمون میں ہم براہ راست تجارتی نظام کی طرف منتقل ہونے کے لئے متعلقہ انٹرایکٹو بروکرز API ہینڈلر کوڈ کرنے جارہے ہیں۔

میں نے پہلے ہی تبادلہ خیال کیا ہے کہ ٹریڈر ورک سٹیشن کو ڈاؤن لوڈ کرنے اور انٹرایکٹو بروکرز ڈیمو اکاؤنٹ بنانے کے ساتھ ساتھ IbPy کا استعمال کرتے ہوئے IB API کے لئے بنیادی انٹرفیس بنانے کا طریقہ۔ یہ مضمون بنیادی IbPy انٹرفیس کو ایونٹ سے چلنے والے نظام میں لپیٹ دے گا ، تاکہ جب یہ براہ راست مارکیٹ فیڈ کے ساتھ جوڑا جائے تو ، یہ خودکار عمل درآمد کے نظام کی بنیاد تشکیل دے گا۔

IBExecutionHandler کلاس کا بنیادی خیال (نیچے ملاحظہ کریں) ایونٹ کی قطار سے آرڈر ایونٹ کی مثالیں وصول کرنا ہے اور پھر ان کو براہ راست انٹرایکٹو بروکرز آرڈر API کے خلاف IbPy لائبریری کا استعمال کرتے ہوئے انجام دینا ہے۔ کلاس API کے ذریعہ واپس بھیجے گئے سرور رسپانس پیغامات کو بھی سنبھالے گی۔ اس مرحلے پر ، صرف ایک ہی کارروائی ہوگی جو متعلقہ FillEvent مثالیں بنانا ہے جو پھر ایونٹ کی قطار میں واپس بھیجا جائے گا۔

کلاس خود ممکنہ طور پر عملدرآمد کی اصلاح کی منطق کے ساتھ ساتھ نفیس غلطی ہینڈلنگ کے ساتھ کافی پیچیدہ بن سکتی ہے۔ تاہم ، میں نے اسے نسبتا simple آسان رکھنے کا انتخاب کیا ہے تاکہ آپ اہم خیالات کو دیکھ سکیں اور اسے اپنی مخصوص تجارتی طرز کے مطابق سمت میں بڑھا سکیں۔

پائیتھون کا نفاذ

ہمیشہ کی طرح ، پہلا کام پائتھون فائل بنانا اور ضروری لائبریریاں درآمد کرنا ہے۔ فائل کو ib_execution.py کہا جاتا ہے اور وہ دوسری ایونٹ سے چلنے والی فائلوں کی طرح اسی ڈائرکٹری میں رہتی ہے۔

ہم ضروری تاریخ / وقت ہینڈلنگ لائبریریوں، IbPy اشیاء اور مخصوص واقعہ اشیاء IBExecutionHandler کی طرف سے سنبھالا جاتا ہے کہ درآمد:

# ib_execution.py

import datetime
import time

from ib.ext.Contract import Contract
from ib.ext.Order import Order
from ib.opt import ibConnection, message

from event import FillEvent, OrderEvent
from execution import ExecutionHandler

اب ہم IBExecutionHandler کلاس کی وضاحت.شروع کریںکنسٹرکٹر سب سے پہلے واقعات کی قطار کے علم کی ضرورت ہوتی ہے۔ اس میں آرڈر_روٹنگ کی وضاحت کی بھی ضرورت ہوتی ہے ، جسے میں نے SMART میں ڈیفالٹ کیا ہے۔ اگر آپ کے پاس مخصوص تبادلہ کی ضروریات ہیں تو ، آپ انہیں یہاں بیان کرسکتے ہیں۔ ڈیفالٹ کرنسی بھی امریکی ڈالر پر مقرر کی گئی ہے۔

اس طریقہ کار کے اندر ہم ایک fill_dict لغت بناتے ہیں ، جو بعد میں FillEvent مثالوں کی تخلیق میں استعمال کے لئے ضروری ہے۔ ہم اپنے کنکشن کی معلومات کو انٹرایکٹو بروکرز API میں اسٹور کرنے کے لئے tws_conn کنکشن آبجیکٹ بھی بناتے ہیں۔ ہمیں ایک ابتدائی ڈیفالٹ آرڈر_آئی ڈی بھی بنانا ہوتا ہے ، جو نقل و حرکت سے بچنے کے لئے تمام بعد کے احکامات کا سراغ لگاتا ہے۔ آخر میں ہم میسج ہینڈلرز کو رجسٹر کرتے ہیں (جس کی وضاحت ہم ذیل میں مزید تفصیل سے کریں گے):

# ib_execution.py

class IBExecutionHandler(ExecutionHandler):
    """
    Handles order execution via the Interactive Brokers
    API, for use against accounts when trading live
    directly.
    """

    def __init__(self, events, 
                 order_routing="SMART", 
                 currency="USD"):
        """
        Initialises the IBExecutionHandler instance.
        """
        self.events = events
        self.order_routing = order_routing
        self.currency = currency
        self.fill_dict = {}

        self.tws_conn = self.create_tws_connection()
        self.order_id = self.create_initial_order_id()
        self.register_handlers()

آئی بی API ایک پیغام پر مبنی واقعہ کا نظام استعمال کرتا ہے جو ہماری کلاس کو مخصوص پیغامات کا جواب دینے کی اجازت دیتا ہے ، جس طرح ایونٹ سے چلنے والے بیک ٹیسٹر کے ساتھ ہی ہوتا ہے۔ میں نے _error_handler طریقہ کے ذریعہ ٹرمینل میں آؤٹ پٹ کے علاوہ ، کوئی حقیقی غلطی ہینڈلنگ (مختصر مقاصد کے لئے) شامل نہیں کی ہے۔

دوسری طرف ، _reply_handler طریقہ کار کا استعمال اس بات کا تعین کرنے کے لئے کیا جاتا ہے کہ آیا FillEvent مثال بنانے کی ضرورت ہے۔ طریقہ کار پوچھتا ہے کہ آیا openOrder پیغام موصول ہوا ہے اور چیک کرتا ہے کہ آیا اس خاص آرڈر ID کے لئے ہمارے fill_dict میں کوئی اندراج پہلے ہی طے شدہ ہے۔ اگر نہیں تو پھر ایک بنایا گیا ہے۔

اگر یہ ایک orderStatus پیغام دیکھتا ہے اور یہ خاص پیغام بیان کرتا ہے کہ آرڈر مکمل ہوچکا ہے ، تو یہ FillEvent تخلیق کرنے کے لئے create_fill کو کال کرتا ہے۔ یہ لاگنگ / ڈیبگ مقاصد کے لئے ٹرمینل میں پیغام بھی آؤٹ پٹ کرتا ہے:

# ib_execution.py
    
    def _error_handler(self, msg):
        """
        Handles the capturing of error messages
        """
        # Currently no error handling.
        print "Server Error: %s" % msg

    def _reply_handler(self, msg):
        """
        Handles of server replies
        """
        # Handle open order orderId processing
        if msg.typeName == "openOrder" and \
            msg.orderId == self.order_id and \
            not self.fill_dict.has_key(msg.orderId):
            self.create_fill_dict_entry(msg)
        # Handle Fills
        if msg.typeName == "orderStatus" and \
            msg.status == "Filled" and \
            self.fill_dict[msg.orderId]["filled"] == False:
            self.create_fill(msg)      
        print "Server Response: %s, %s\n" % (msg.typeName, msg)

مندرجہ ذیل طریقہ ، create_tws_connection ، IbPy ibConnection آبجیکٹ کا استعمال کرتے ہوئے IB API سے رابطہ قائم کرتا ہے۔ یہ 7496 کی ڈیفالٹ پورٹ اور 10 کی ڈیفالٹ کلائنٹ ID کا استعمال کرتا ہے۔ ایک بار جب آبجیکٹ بن جاتا ہے تو ، رابطہ قائم کرنے کا طریقہ رابطہ قائم کرنے کے لئے کہا جاتا ہے:

# ib_execution.py
    
    def create_tws_connection(self):
        """
        Connect to the Trader Workstation (TWS) running on the
        usual port of 7496, with a clientId of 10.
        The clientId is chosen by us and we will need 
        separate IDs for both the execution connection and
        market data connection, if the latter is used elsewhere.
        """
        tws_conn = ibConnection()
        tws_conn.connect()
        return tws_conn

علیحدہ احکامات کا سراغ لگانے کے لئے (تعاقب بھرنے کے مقاصد کے لئے) مندرجہ ذیل طریقہ create_initial_order_id استعمال کیا جاتا ہے۔ میں نے اسے 1 پر ڈیفالٹ کیا ہے ، لیکن ایک زیادہ نفیس نقطہ نظر تازہ ترین دستیاب ID کے لئے IB استفسار کرنا اور اس کا استعمال کرنا ہوگا۔ آپ ہمیشہ ٹریڈر ورک سٹیشن > عالمی ترتیب > API ترتیبات پینل کے ذریعے موجودہ API آرڈر ID کو ری سیٹ کرسکتے ہیں:

# ib_execution.py
    
    def create_initial_order_id(self):
        """
        Creates the initial order ID used for Interactive
        Brokers to keep track of submitted orders.
        """
        # There is scope for more logic here, but we
        # will use "1" as the default for now.
        return 1

مندرجہ ذیل طریقہ، register_handlers، صرف TWS کنکشن کے ساتھ غلطی اور جواب ہینڈلر طریقوں کو اوپر بیان کیا رجسٹر کرتا ہے:

# ib_execution.py
    
    def register_handlers(self):
        """
        Register the error and server reply 
        message handling functions.
        """
        # Assign the error handling function defined above
        # to the TWS connection
        self.tws_conn.register(self._error_handler, 'Error')

        # Assign all of the server reply messages to the
        # reply_handler function defined above
        self.tws_conn.registerAll(self._reply_handler)

آئی بی پی کا استعمال کرنے کے بارے میں پچھلے ٹیوٹوریل کی طرح ہمیں بھی معاہدہ کی مثال بنانے کی ضرورت ہے اور پھر اسے آرڈر کی مثال کے ساتھ جوڑنا ہے ، جو آئی بی اے پی آئی کو بھیجا جائے گا۔ مندرجہ ذیل طریقہ ، تخلیق_ معاہدہ ، اس جوڑے کا پہلا جزو تیار کرتا ہے۔ اس سے ٹکر علامت ، سیکیورٹی کی قسم (جیسے اسٹاک یا مستقبل) ، تبادلہ / بنیادی تبادلہ اور کرنسی کی توقع ہوتی ہے۔ یہ معاہدہ کی مثال واپس کرتا ہے:

# ib_execution.py
    
    def create_contract(self, symbol, sec_type, exch, prim_exch, curr):
        """
        Create a Contract object defining what will
        be purchased, at which exchange and in which currency.

        symbol - The ticker symbol for the contract
        sec_type - The security type for the contract ('STK' is 'stock')
        exch - The exchange to carry out the contract on
        prim_exch - The primary exchange to carry out the contract on
        curr - The currency in which to purchase the contract
        """
        contract = Contract()
        contract.m_symbol = symbol
        contract.m_secType = sec_type
        contract.m_exchange = exch
        contract.m_primaryExch = prim_exch
        contract.m_currency = curr
        return contract

مندرجہ ذیل طریقہ ، create_order ، جوڑی کا دوسرا جزو ، یعنی آرڈر کی مثال تیار کرتا ہے۔ یہ آرڈر کی قسم (جیسے مارکیٹ یا حد) ، تجارت کرنے کے لئے اثاثہ کی مقدار اور action (خرید یا فروخت) کی توقع کرتا ہے۔ یہ آرڈر کی مثال واپس کرتا ہے:

# ib_execution.py
    
    def create_order(self, order_type, quantity, action):
        """
        Create an Order object (Market/Limit) to go long/short.

        order_type - 'MKT', 'LMT' for Market or Limit orders
        quantity - Integral number of assets to order
        action - 'BUY' or 'SELL'
        """
        order = Order()
        order.m_orderType = order_type
        order.m_totalQuantity = quantity
        order.m_action = action
        return order

کسی خاص آرڈر آئی ڈی کے لئے فل ایونٹ مثالوں کی نقل و حرکت سے بچنے کے ل we ، ہم کسی خاص آرڈر آئی ڈی سے ملنے والی چابیاں ذخیرہ کرنے کے لئے فل_ڈکٹ نامی لغت کا استعمال کرتے ہیں۔ جب فل پیدا ہوجاتا ہے تو کسی خاص آرڈر آئی ڈی کے لئے کسی اندراج کی فائلڈ کلید کو سچ پر مقرر کیا جاتا ہے۔ اگر آئی بی سے بعد میں سرور رسپانس پیغام موصول ہوتا ہے جس میں بتایا گیا ہے کہ کوئی آرڈر بھرا ہوا ہے (اور یہ ایک نقل شدہ پیغام ہے) تو اس سے نئی بھرتی نہیں ہوگی۔ مندرجہ ذیل طریقہ create_fill_dict_entry اس کو انجام دیتا ہے:

# ib_execution.py
    
    def create_fill_dict_entry(self, msg):
        """
        Creates an entry in the Fill Dictionary that lists 
        orderIds and provides security information. This is
        needed for the event-driven behaviour of the IB
        server message behaviour.
        """
        self.fill_dict[msg.orderId] = {
            "symbol": msg.contract.m_symbol,
            "exchange": msg.contract.m_exchange,
            "direction": msg.order.m_action,
            "filled": False
        }

مندرجہ ذیل طریقہ، create_fill، اصل میں FillEvent مثال تخلیق کرتا ہے اور اسے واقعات کی قطار میں رکھتا ہے:

# ib_execution.py
    
    def create_fill(self, msg):
        """
        Handles the creation of the FillEvent that will be
        placed onto the events queue subsequent to an order
        being filled.
        """
        fd = self.fill_dict[msg.orderId]

        # Prepare the fill data
        symbol = fd["symbol"]
        exchange = fd["exchange"]
        filled = msg.filled
        direction = fd["direction"]
        fill_cost = msg.avgFillPrice

        # Create a fill event object
        fill = FillEvent(
            datetime.datetime.utcnow(), symbol, 
            exchange, filled, direction, fill_cost
        )

        # Make sure that multiple messages don't create
        # additional fills.
        self.fill_dict[msg.orderId]["filled"] = True

        # Place the fill event onto the event queue
        self.events.put(fill_event)

اب جب کہ مذکورہ بالا تمام طریقوں کو نافذ کیا گیا ہے ، اب بھی ExecutionHandler تجریدی بیس کلاس سے execute_order طریقہ کو کالعدم کرنا باقی ہے۔ یہ طریقہ اصل میں IB API کے ساتھ آرڈر کی جگہ لے لیتا ہے۔

ہم سب سے پہلے چیک کرتے ہیں کہ اس طریقہ کار کو موصول ہونے والا واقعہ واقعی آرڈر ایونٹ ہے اور پھر معاہدہ اور آرڈر اشیاء کو ان کے متعلقہ پیرامیٹرز کے ساتھ تیار کرتے ہیں۔ ایک بار جب دونوں بنائے جاتے ہیں تو ، کنکشن آبجیکٹ کا IbPy طریقہ placeOrder اس سے وابستہ order_id کے ساتھ بلایا جاتا ہے۔

یہ یقینی بنانے کے لئے کہ آرڈر واقعی آئی بی تک جاتا ہے اس وقت.sleep(1) طریقہ کار کو فون کرنا انتہائی ضروری ہے۔ اس لائن کو ہٹانے سے ای پی آئی کا inconsistent رویہ پیدا ہوتا ہے ، کم از کم میرے سسٹم پر!

آخر میں، ہم آرڈر آئی ڈی میں اضافہ کرتے ہیں تاکہ ہم اس بات کو یقینی بنائیں کہ ہم آرڈر کی نقل نہ کریں:

# ib_execution.py
    
    def execute_order(self, event):
        """
        Creates the necessary InteractiveBrokers order object
        and submits it to IB via their API.

        The results are then queried in order to generate a
        corresponding Fill object, which is placed back on
        the event queue.

        Parameters:
        event - Contains an Event object with order information.
        """
        if event.type == 'ORDER':
            # Prepare the parameters for the asset order
            asset = event.symbol
            asset_type = "STK"
            order_type = event.order_type
            quantity = event.quantity
            direction = event.direction

            # Create the Interactive Brokers contract via the 
            # passed Order event
            ib_contract = self.create_contract(
                asset, asset_type, self.order_routing,
                self.order_routing, self.currency
            )

            # Create the Interactive Brokers order via the 
            # passed Order event
            ib_order = self.create_order(
                order_type, quantity, direction
            )

            # Use the connection to the send the order to IB
            self.tws_conn.placeOrder(
                self.order_id, ib_contract, ib_order
            )

            # NOTE: This following line is crucial.
            # It ensures the order goes through!
            time.sleep(1)

            # Increment the order ID for this session
            self.order_id += 1

یہ کلاس ایک انٹرایکٹو بروکرز ایگزیکشن ہینڈلر کی بنیاد بناتی ہے اور اسے نقلی ایگزیکشن ہینڈلر کی جگہ استعمال کیا جاسکتا ہے ، جو صرف بیک ٹیسٹنگ کے لئے موزوں ہے۔ تاہم ، آئی بی ہینڈلر کو استعمال کرنے سے پہلے ، بیک ٹیسٹر سسٹم کے تاریخی ڈیٹا فیڈ ہینڈلر کی جگہ لینا ایک رواں مارکیٹ فیڈ ہینڈلر بنانا ضروری ہے۔ یہ مستقبل کے مضمون کا موضوع ہوگا۔

اس طرح ہم بیک ٹیسٹ اور لائیو سسٹم سے زیادہ سے زیادہ دوبارہ استعمال کر رہے ہیں تاکہ یہ یقینی بنایا جا سکے کہ کوڈ سوائپ آؤٹ کم سے کم ہو اور اس طرح دونوں میں رویہ اسی طرح کا ہو، اگر ایک جیسا نہ ہو۔


مزید