بیک ٹیسٹنگ تاریخی اعداد و شمار پر تجارتی حکمت عملی کے خیال کو لاگو کرنے کا تحقیقی عمل ہے تاکہ ماضی کی کارکردگی کا تعین کیا جاسکے۔ خاص طور پر ، بیک ٹیسٹر حکمت عملی کی مستقبل کی کارکردگی کے بارے میں کوئی ضمانت نہیں دیتا ہے۔ تاہم ، وہ حکمت عملی پائپ لائن ریسرچ کے عمل کا ایک ضروری جزو ہیں ، جس سے پیداوار میں ڈالنے سے پہلے حکمت عملیوں کو فلٹر کرنے کی اجازت ملتی ہے۔
اس مضمون میں (اور اس کے بعد آنے والے) پیتھون میں لکھے گئے ایک بنیادی آبجیکٹ پر مبنی بیک ٹیسٹنگ سسٹم کا خاکہ پیش کیا جائے گا۔ یہ ابتدائی نظام بنیادی طور پر
ایک مضبوط بیک ٹیسٹنگ سسٹم ڈیزائن کرنے کا عمل انتہائی مشکل ہے۔ ایک الگورتھمک ٹریڈنگ سسٹم کی کارکردگی کو متاثر کرنے والے تمام اجزاء کی موثر انداز میں تقلید کرنا ایک چیلنج ہے۔ ناقص ڈیٹا گرانولرٹی ، بروکر پر آرڈر روٹنگ کی عدم شفافیت ، آرڈر لیٹینسی اور بہت سارے دیگر عوامل ایک حکمت عملی کی
بیک ٹسٹنگ سسٹم تیار کرتے وقت اسے مستقل طور پر دوبارہ لکھنا چاہتے ہیں کیونکہ کارکردگی کا اندازہ کرنے میں مزید عوامل اہم پائے جاتے ہیں۔ بیک ٹسٹنگ کا کوئی نظام کبھی بھی مکمل نہیں ہوتا ہے اور ترقی کے دوران کسی مقام پر یہ فیصلہ کرنا ضروری ہے کہ کافی عوامل کو سسٹم کے ذریعہ قبضہ کرلیا گیا ہے۔
ان خدشات کو ذہن میں رکھتے ہوئے ، یہاں پیش کردہ بیک ٹیسٹر کچھ حد تک آسان ہوگا۔ جیسا کہ ہم مزید امور (پورٹ فولیو کی اصلاح ، رسک مینجمنٹ ، ٹرانزیکشن لاگت ہینڈلنگ) کا جائزہ لیتے ہیں ، بیک ٹیسٹر زیادہ مضبوط ہوجائے گا۔
عام طور پر دو قسم کے بیک ٹیسٹنگ سسٹم ہیں جو دلچسپی کا باعث ہوں گے۔ پہلا تحقیق پر مبنی ہے ، بنیادی طور پر ابتدائی مراحل میں استعمال ہوتا ہے ، جہاں زیادہ سنجیدہ تشخیص کے ل those ان کا انتخاب کرنے کے لئے بہت سی حکمت عملیوں کا تجربہ کیا جائے گا۔ یہ ریسرچ بیک ٹیسٹنگ سسٹم اکثر پائتھون ، آر یا میٹ لیب میں لکھے جاتے ہیں کیونکہ اس مرحلے میں ترقی کی رفتار عملدرآمد کی رفتار سے زیادہ اہم ہے۔
دوسری قسم کا بیک ٹیسٹنگ سسٹم ایونٹ پر مبنی ہے۔ یعنی ، یہ بیک ٹیسٹنگ کے عمل کو خود ہی ٹریڈنگ ایگزیکشن سسٹم کی طرح (اگر بالکل یکساں نہیں) ایک عملدرآمد لوپ میں انجام دیتا ہے۔ یہ حکمت عملی کی زیادہ سخت تشخیص فراہم کرنے کے لئے مارکیٹ کے اعداد و شمار اور آرڈر کی عملدرآمد کے عمل کو حقیقت پسندانہ طور پر ماڈل کرے گا۔
آخری نظام اکثر C ++ یا جاوا جیسی اعلی کارکردگی کی زبان میں لکھے جاتے ہیں ، جہاں عملدرآمد کی رفتار ضروری ہے۔ کم تعدد کی حکمت عملیوں کے لئے (اگرچہ ابھی بھی دن کے اندر) ، اس تناظر میں استعمال کرنے کے لئے پائیٹون کافی سے زیادہ ہے۔
اب ایک آبجیکٹ پر مبنی تحقیق پر مبنی بیک ٹیسٹنگ ماحول کے ڈیزائن اور نفاذ پر تبادلہ خیال کیا جائے گا۔ مندرجہ ذیل وجوہات کی بناء پر آبجیکٹ پر مبنی سافٹ ویئر ڈیزائن پیراگراف کے طور پر منتخب کیا گیا ہے۔
اس مرحلے میں بیک ٹیسٹر کو حقیقی مارکیٹ کی درستگی کی قیمت پر ، عمل درآمد میں آسانی اور مناسب حد تک لچک کے لئے ڈیزائن کیا گیا ہے۔ خاص طور پر ، یہ بیک ٹیسٹر صرف ایک ہی آلہ پر کام کرنے والی حکمت عملیوں کو سنبھال سکے گا۔ بعد میں بیک ٹیسٹر کو آلات کے سیٹوں کو سنبھالنے کے لئے تبدیل کیا جائے گا۔ ابتدائی بیک ٹیسٹر کے لئے ، درج ذیل اجزاء کی ضرورت ہوتی ہے۔
جیسا کہ دیکھا جاسکتا ہے ، اس بیک ٹیسٹر میں پورٹ فولیو / رسک مینجمنٹ ، عملدرآمد ہینڈلنگ (یعنی کوئی حد کے احکامات) کا کوئی حوالہ شامل نہیں ہے اور نہ ہی یہ لین دین کے اخراجات کی نفیس ماڈلنگ فراہم کرے گا۔ اس مرحلے میں یہ زیادہ مسئلہ نہیں ہے۔ اس سے ہمیں آبجیکٹ پر مبنی بیک ٹیسٹر اور پانڈاس / نمپی لائبریریوں کی تخلیق کے عمل سے واقفیت حاصل کرنے کی اجازت ملتی ہے۔ وقت کے ساتھ اس میں بہتری آئے گی۔
اب ہم ہر اعتراض کے لئے نفاذ کا خاکہ پیش کرنے کے لئے آگے بڑھیں گے.
اس مرحلے پر حکمت عملی کا اعتراض کافی عام ہونا ضروری ہے ، کیونکہ یہ پیش گوئی ، اوسط ریورس ، رفتار اور اتار چڑھاؤ کی حکمت عملیوں کو سنبھالے گا۔ یہاں جن حکمت عملیوں پر غور کیا جارہا ہے وہ ہمیشہ ٹائم سیریز پر مبنی ہوں گے ، یعنی
حکمت عملی کلاس ہمیشہ سگنل کی سفارشات بھی تیار کرے گی۔ اس کا مطلب یہ ہے کہ یہ ایک پورٹ فولیو مثال کو طویل / مختصر جانے یا پوزیشن رکھنے کے معنی میں مشورہ دے گا۔ یہ لچک ہمیں متعدد حکمت عملی
کلاسوں کے انٹرفیس کو ایک تجریدی بیس کلاس طریقہ کار کا استعمال کرتے ہوئے نافذ کیا جائے گا۔ ایک تجریدی بیس کلاس ایک ایسا اعتراض ہے جس کی مثال نہیں دی جاسکتی ہے اور اس طرح صرف مشتق کلاسیں تشکیل دی جاسکتی ہیں۔ پائتھون کوڈ ذیل میں ایک فائل میں دیا گیا ہے جسے کہا جاتا ہے۔backtest.py. اسٹریٹیجی کلاس کی ضرورت ہے کہ کسی بھی ذیلی کلاس کو generate_signals طریقہ کار کو لاگو کرنا چاہئے.
اسٹریٹیجی کلاس کو براہ راست انسٹال ہونے سے روکنے کے لئے (چونکہ یہ تجریدی ہے!) ، abc ماڈیول سے ABCMeta اور abstractmethod اشیاء کا استعمال کرنا ضروری ہے۔ ہم کلاس کی ایک خصوصیت مقرر کرتے ہیں ، جسے کہا جاتا ہے۔میٹا کلاسکے برابر ہونا ABCMeta اور پھر abstractmethod decorator کے ساتھ generate_signals طریقہ کو سجانے.
# backtest.py
from abc import ABCMeta, abstractmethod
class Strategy(object):
"""Strategy is an abstract base class providing an interface for
all subsequent (inherited) trading strategies.
The goal of a (derived) Strategy object is to output a list of signals,
which has the form of a time series indexed pandas DataFrame.
In this instance only a single symbol/instrument is supported."""
__metaclass__ = ABCMeta
@abstractmethod
def generate_signals(self):
"""An implementation is required to return the DataFrame of symbols
containing the signals to go long, short or hold (1, -1 or 0)."""
raise NotImplementedError("Should implement generate_signals()!")
اگرچہ مذکورہ بالا انٹرفیس براہ راست ہے ، لیکن جب اس کلاس کو ہر مخصوص قسم کی حکمت عملی کے لئے وراثت میں دیا جاتا ہے تو یہ زیادہ پیچیدہ ہوجاتا ہے۔ آخر کار اس ترتیب میں حکمت عملی کلاس کا مقصد ہر آلہ کے لئے طویل / مختصر / ہولڈ سگنل کی فہرست فراہم کرنا ہے جو کسی پورٹ فولیو میں بھیجا جائے گا۔
پورٹ فولیو کلاس وہ جگہ ہے جہاں تجارتی منطق کی اکثریت واقع ہوگی۔ اس ریسرچ بیک ٹیسٹر کے لئے پورٹ فولیو پوزیشن سائزنگ ، رسک تجزیہ ، ٹرانزیکشن لاگت مینجمنٹ اور عملدرآمد ہینڈلنگ (یعنی مارکیٹ آن اوپن ، مارکیٹ آن بند آرڈرز) کا تعین کرنے کا ذمہ دار ہے۔ بعد کے مرحلے میں ان کاموں کو الگ الگ اجزاء میں تقسیم کیا جائے گا۔ ابھی وہ ایک کلاس میں رول ہوں گے۔
یہ کلاس پانڈا کا بھرپور استعمال کرتی ہے اور اس کی ایک عمدہ مثال فراہم کرتی ہے جہاں لائبریری بہت زیادہ وقت کی بچت کرسکتی ہے ، خاص طور پر
پورٹ فولیو کلاس کا مقصد آخر کار تجارتوں کی ایک ترتیب اور ایکوئٹی وکر تیار کرنا ہے ، جس کا تجزیہ کارکردگی کلاس کرے گی۔ اس کے حصول کے ل it اسے حکمت عملی کے اعتراض سے تجارتی سفارشات کی فہرست فراہم کی جانی چاہئے۔ بعد میں ، یہ حکمت عملی کے اشیاء کا ایک گروپ ہوگا۔
پورٹ فولیو کلاس کو یہ بتانے کی ضرورت ہوگی کہ ٹریڈنگ سگنلز کے ایک خاص سیٹ کے لئے سرمایہ کو کس طرح تعینات کیا جائے ، لین دین کے اخراجات کو کس طرح سنبھالنا ہے اور کس قسم کے آرڈرز کا استعمال کیا جائے گا۔ حکمت عملی کا مقصد اعداد و شمار کی سلاخوں پر کام کر رہا ہے اور اس طرح کسی آرڈر کے عمل درآمد پر حاصل ہونے والی قیمتوں کے بارے میں مفروضے کیے جانے چاہئیں۔ چونکہ کسی بھی سلاخ کی اعلی / کم قیمت پہلے سے نامعلوم ہے لہذا تجارت کے لئے صرف کھلی اور بند قیمتوں کا استعمال کرنا ممکن ہے۔ حقیقت میں یہ یقینی بنانا ناممکن ہے کہ مارکیٹ آرڈر کا استعمال کرتے وقت کسی آرڈر کو ان مخصوص قیمتوں میں سے کسی ایک پر پورا کیا جائے گا ، لہذا یہ ، بہترین صورت میں ، ایک تخمینہ ہوگا۔
احکامات کو پورا کرنے کے بارے میں مفروضوں کے علاوہ ، یہ بیک ٹیسٹر مارجن / بروکرج پابندیوں کے تمام تصورات کو نظرانداز کرے گا اور یہ فرض کرے گا کہ کسی بھی آلہ میں بغیر کسی لیکویڈیٹی پابندیوں کے آزادانہ طور پر طویل اور مختصر جانا ممکن ہے۔ یہ واضح طور پر ایک بہت ہی غیر حقیقی مفروضہ ہے ، لیکن یہ ایک ہے جسے بعد میں نرمی دی جاسکتی ہے۔
درج ذیل فہرست جاری ہےbacktest.py:
# backtest.py
class Portfolio(object):
"""An abstract base class representing a portfolio of
positions (including both instruments and cash), determined
on the basis of a set of signals provided by a Strategy."""
__metaclass__ = ABCMeta
@abstractmethod
def generate_positions(self):
"""Provides the logic to determine how the portfolio
positions are allocated on the basis of forecasting
signals and available cash."""
raise NotImplementedError("Should implement generate_positions()!")
@abstractmethod
def backtest_portfolio(self):
"""Provides the logic to generate the trading orders
and subsequent equity curve (i.e. growth of total equity),
as a sum of holdings and cash, and the bar-period returns
associated with this curve based on the 'positions' DataFrame.
Produces a portfolio object that can be examined by
other classes/functions."""
raise NotImplementedError("Should implement backtest_portfolio()!")
اس مرحلے میں حکمت عملی اور پورٹ فولیو خلاصہ بیس کلاس متعارف کروائے گئے ہیں۔ اب ہم کام کرنے والی
ہم اسٹریٹیجی کا ایک ذیلی طبقہ تیار کرکے شروع کریں گے جسے رینڈم فورکاسٹ اسٹریٹیجی کہا جاتا ہے ، جس کا واحد کام تصادفی طور پر منتخب کردہ طویل / مختصر سگنل تیار کرنا ہے۔ اگرچہ یہ واضح طور پر ایک بے معنی تجارتی حکمت عملی ہے ، لیکن یہ آبجیکٹ پر مبنی بیک ٹیسٹنگ فریم ورک کا مظاہرہ کرکے ہماری ضروریات کو پورا کرے گا۔ اس طرح ہم random_forecast.py نامی ایک نئی فائل شروع کریں گے ، جس میں بے ترتیب پیش گوئی کرنے والے کی فہرست درج ذیل ہے:
# random_forecast.py
import numpy as np
import pandas as pd
import Quandl # Necessary for obtaining financial data easily
from backtest import Strategy, Portfolio
class RandomForecastingStrategy(Strategy):
"""Derives from Strategy to produce a set of signals that
are randomly generated long/shorts. Clearly a nonsensical
strategy, but perfectly acceptable for demonstrating the
backtesting infrastructure!"""
def __init__(self, symbol, bars):
"""Requires the symbol ticker and the pandas DataFrame of bars"""
self.symbol = symbol
self.bars = bars
def generate_signals(self):
"""Creates a pandas DataFrame of random signals."""
signals = pd.DataFrame(index=self.bars.index)
signals['signal'] = np.sign(np.random.randn(len(signals)))
# The first five elements are set to zero in order to minimise
# upstream NaN errors in the forecaster.
signals['signal'][0:5] = 0.0
return signals
اب جب ہمارے پاس
پورٹ فولیو آبجیکٹ ، اگرچہ اس کے انٹرفیس میں انتہائی لچکدار ہے ، اس کے بارے میں مخصوص انتخاب کی ضرورت ہوتی ہے کہ کس طرح لین دین کی لاگت ، مارکیٹ آرڈرز وغیرہ کو سنبھالنا ہے۔ اس بنیادی مثال میں میں نے غور کیا ہے کہ بغیر کسی پابندی یا مارجن کے کسی آلے کو آسانی سے طویل / مختصر کرنا ، بار کی کھلی قیمت پر براہ راست خریدنا یا فروخت کرنا ، لین دین کے صفر اخراجات (جس میں سلائڈج ، فیس اور مارکیٹ کے اثرات شامل ہیں) اور ہر تجارت کے لئے براہ راست خریدنے کے لئے اسٹاک کی مقدار کی وضاحت کی ہے۔
یہاں random_forecast.py فہرست کا تسلسل ہے:
# random_forecast.py
class MarketOnOpenPortfolio(Portfolio):
"""Inherits Portfolio to create a system that purchases 100 units of
a particular symbol upon a long/short signal, assuming the market
open price of a bar.
In addition, there are zero transaction costs and cash can be immediately
borrowed for shorting (no margin posting or interest requirements).
Requires:
symbol - A stock symbol which forms the basis of the portfolio.
bars - A DataFrame of bars for a symbol set.
signals - A pandas DataFrame of signals (1, 0, -1) for each symbol.
initial_capital - The amount in cash at the start of the portfolio."""
def __init__(self, symbol, bars, signals, initial_capital=100000.0):
self.symbol = symbol
self.bars = bars
self.signals = signals
self.initial_capital = float(initial_capital)
self.positions = self.generate_positions()
def generate_positions(self):
"""Creates a 'positions' DataFrame that simply longs or shorts
100 of the particular symbol based on the forecast signals of
{1, 0, -1} from the signals DataFrame."""
positions = pd.DataFrame(index=signals.index).fillna(0.0)
positions[self.symbol] = 100*signals['signal']
return positions
def backtest_portfolio(self):
"""Constructs a portfolio from the positions DataFrame by
assuming the ability to trade at the precise market open price
of each bar (an unrealistic assumption!).
Calculates the total of cash and the holdings (market price of
each position per bar), in order to generate an equity curve
('total') and a set of bar-based returns ('returns').
Returns the portfolio object to be used elsewhere."""
# Construct the portfolio DataFrame to use the same index
# as 'positions' and with a set of 'trading orders' in the
# 'pos_diff' object, assuming market open prices.
portfolio = self.positions*self.bars['Open']
pos_diff = self.positions.diff()
# Create the 'holdings' and 'cash' series by running through
# the trades and adding/subtracting the relevant quantity from
# each column
portfolio['holdings'] = (self.positions*self.bars['Open']).sum(axis=1)
portfolio['cash'] = self.initial_capital - (pos_diff*self.bars['Open']).sum(axis=1).cumsum()
# Finalise the total and bar-based returns based on the 'cash'
# and 'holdings' figures for the portfolio
portfolio['total'] = portfolio['cash'] + portfolio['holdings']
portfolio['returns'] = portfolio['total'].pct_change()
return portfolio
اس سے ہمیں اس طرح کے نظام پر مبنی ایکوئٹی وکر پیدا کرنے کے لئے درکار ہر چیز مل جاتی ہے۔ آخری مرحلہ یہ ہے کہ اس سب کو ایک ساتھ باندھنااہمفنکشن:
if __name__ == "__main__":
# Obtain daily bars of SPY (ETF that generally
# follows the S&P500) from Quandl (requires 'pip install Quandl'
# on the command line)
symbol = 'SPY'
bars = Quandl.get("GOOG/NYSE_%s" % symbol, collapse="daily")
# Create a set of random forecasting signals for SPY
rfs = RandomForecastingStrategy(symbol, bars)
signals = rfs.generate_signals()
# Create a portfolio of SPY
portfolio = MarketOnOpenPortfolio(symbol, bars, signals, initial_capital=100000.0)
returns = portfolio.backtest_portfolio()
print returns.tail(10)
پروگرام کا آؤٹ پٹ مندرجہ ذیل ہے۔ آپ کا انتخاب کردہ تاریخ کی حد اور استعمال شدہ بے ترتیب بیج پر منحصر ہے:
SPY holdings cash total returns
تاریخ
2014-01-02 -18398 -18398 111486 93088 0.000097
2014-01-03 18321 18321 74844 93165 0.000827
2014-01-06 18347 18347 74844 93191 0.000279
2014-01-07 18309 18309 74844 93153 -0.000408
2014-01-08 -18345 -18345 111534 93189 0.000386
2014-01-09 -18410 -18410 111534 93124 -0.000698
2014-01-10 -18395 -18395 111534 93139 0.000161
2014-01-13 -18371 -18371 111534 93163 0.000258
2014-01-14 -18228 -18228 111534 93306 0.001535
2014-01-15 18410 18410 74714 93124 -0.001951
اس مثال میں حکمت عملی نے پیسہ کھویا ، جو پیش گوئی کرنے والے کی اسٹوکاسٹک نوعیت کو دیکھتے ہوئے حیرت کی بات نہیں ہے۔ اگلے اقدامات ایک کارکردگی کا اعتراض بنانا ہے جو پورٹ فولیو کی مثال کو قبول کرتا ہے اور کارکردگی کی پیمائش کی فہرست فراہم کرتا ہے جس پر حکمت عملی کو فلٹر کرنے یا نہ کرنے کا فیصلہ کرنا ہے۔
ہم پورٹ فولیو آبجیکٹ کو بھی بہتر بنا سکتے ہیں تاکہ ٹرانزیکشن کے اخراجات (جیسے انٹرایکٹو بروکرز کمیشن اور سلائپج) کو زیادہ حقیقت پسندانہ طریقے سے سنبھال سکیں۔ ہم آسانی سے ایک پیشن گوئی انجن کو حکمت عملی آبجیکٹ میں شامل کرسکتے ہیں ، جس سے (امید ہے کہ) بہتر نتائج برآمد ہوں گے۔ اگلے مضامین میں ہم ان تصورات کو مزید گہرائی سے دریافت کریں گے۔