পান্ডার সাথে পাইথনে ব্যাকটেস্টিং পরিবেশগুলি গবেষণা করুন

লেখক:ভাল, তৈরিঃ 2019-03-16 11:58:20, আপডেটঃ

ব্যাকটেস্টিং হ'ল অতীতের পারফরম্যান্স নিশ্চিত করার জন্য historicalতিহাসিক ডেটাতে একটি ট্রেডিং কৌশল ধারণা প্রয়োগের গবেষণা প্রক্রিয়া। বিশেষত, ব্যাকটেস্টার কৌশলটির ভবিষ্যতের পারফরম্যান্স সম্পর্কে কোনও গ্যারান্টি দেয় না। তবে তারা কৌশল পাইপলাইন গবেষণা প্রক্রিয়াটির একটি প্রয়োজনীয় উপাদান, যা কৌশলগুলিকে উত্পাদনে রাখার আগে ফিল্টার করা সম্ভব করে।

এই নিবন্ধে (এবং এর পরে) পাইথনে লিখিত একটি মৌলিক অবজেক্ট-ভিত্তিক ব্যাকটেস্টিং সিস্টেম বর্ণনা করা হবে। এই প্রাথমিক সিস্টেমটি প্রাথমিকভাবে একটি শিক্ষা সহায়তা হবে, যা ব্যাকটেস্টিং সিস্টেমের বিভিন্ন উপাদানগুলি প্রদর্শন করতে ব্যবহৃত হয়। আমরা নিবন্ধগুলির মধ্য দিয়ে অগ্রসর হওয়ার সাথে সাথে আরও পরিশীলিত কার্যকারিতা যুক্ত করা হবে।

ব্যাকটেস্টিং ওভারভিউ

একটি শক্তিশালী ব্যাকটেস্টিং সিস্টেম ডিজাইন করার প্রক্রিয়াটি অত্যন্ত কঠিন। একটি অ্যালগরিদমিক ট্রেডিং সিস্টেমের কর্মক্ষমতা প্রভাবিত করে এমন সমস্ত উপাদানকে কার্যকরভাবে সিমুলেট করা চ্যালেঞ্জিং। দরিদ্র ডেটা গ্রানুলারিটি, ব্রোকারে অর্ডার রুটিংয়ের অপ্রকাশ্যতা, অর্ডার লেটেন্সি এবং অন্যান্য অনেকগুলি কারণ কৌশলটির true কর্মক্ষমতা ব্যাকটেস্টেড কর্মক্ষমতার বিপরীতে পরিবর্তনের জন্য ষড়যন্ত্র করে।

একটি ব্যাকটেস্টিং সিস্টেম বিকাশের সময় এটি ক্রমাগত পুনরায় লিখতে চাইতে প্রলুব্ধ হয় কারণ কর্মক্ষমতা মূল্যায়নে আরও কারণগুলি গুরুত্বপূর্ণ বলে মনে করা হয়। কোনও ব্যাকটেস্টিং সিস্টেম কখনও শেষ হয় না এবং বিকাশের সময় একটি বিচার করা উচিত যে যথেষ্ট কারণগুলি সিস্টেম দ্বারা ধরা পড়েছে।

এই উদ্বেগগুলি মাথায় রেখে এখানে উপস্থাপিত ব্যাকটেস্টারটি কিছুটা সরলীকৃত হবে। আমরা আরও বিষয়গুলি (পোর্টফোলিও অপ্টিমাইজেশন, ঝুঁকি ব্যবস্থাপনা, লেনদেনের ব্যয় পরিচালনা) অন্বেষণ করার সাথে সাথে ব্যাকটেস্টার আরও শক্তিশালী হয়ে উঠবে।

ব্যাকটেস্টিং সিস্টেমের ধরন

সাধারণত দুটি ধরণের ব্যাকটেস্টিং সিস্টেম রয়েছে যা আগ্রহী হবে। প্রথমটি গবেষণা ভিত্তিক, প্রাথমিক পর্যায়ে ব্যবহৃত হয়, যেখানে আরও গুরুতর মূল্যায়নের জন্য সেগুলি নির্বাচন করার জন্য অনেক কৌশল পরীক্ষা করা হবে। এই গবেষণা ব্যাকটেস্টিং সিস্টেমগুলি প্রায়শই পাইথন, আর বা ম্যাটল্যাবে লেখা হয় কারণ এই পর্যায়ে বিকাশের গতি কার্যকরকরণের গতির চেয়ে বেশি গুরুত্বপূর্ণ।

দ্বিতীয় ধরণের ব্যাকটেস্টিং সিস্টেমটি ইভেন্ট-ভিত্তিক। অর্থাৎ, এটি ট্রেডিং এক্সিকিউশন সিস্টেমের মতো (যদি না একই রকম) একটি এক্সিকিউশন লুপে ব্যাকটেস্টিং প্রক্রিয়াটি সম্পাদন করে। এটি কৌশলটির আরও কঠোর মূল্যায়ন সরবরাহ করার জন্য বাজারের ডেটা এবং অর্ডার এক্সিকিউশন প্রক্রিয়াটিকে বাস্তবসম্মতভাবে মডেল করবে।

শেষের সিস্টেমগুলি প্রায়শই সি ++ বা জাভা এর মতো উচ্চ-কার্যকারিতা ভাষায় লেখা হয়, যেখানে কার্যকরকরণের গতি অপরিহার্য। নিম্ন ফ্রিকোয়েন্সি কৌশলগুলির জন্য (যদিও এখনও ইনট্রাডে), পাইথন এই প্রসঙ্গে ব্যবহারের জন্য যথেষ্ট পরিমাণে।

পাইথনে অবজেক্ট-ওরিয়েন্টেড রিসার্চ ব্যাকটেস্টার

এখন একটি অবজেক্ট-ভিত্তিক গবেষণা ভিত্তিক ব্যাকটেস্টিং পরিবেশের নকশা এবং বাস্তবায়ন নিয়ে আলোচনা করা হবে। নিম্নলিখিত কারণগুলির জন্য অবজেক্ট-ভিত্তিক সফ্টওয়্যার ডিজাইনের দৃষ্টান্ত হিসাবে বেছে নেওয়া হয়েছেঃ

  • প্রতিটি উপাদান ইন্টারফেস আগাম নির্দিষ্ট করা যেতে পারে, যখন প্রতিটি উপাদান অভ্যন্তরীণ পরিবর্তন করা যেতে পারে (বা প্রতিস্থাপিত) প্রকল্প অগ্রগতি হিসাবে
  • ইন্টারফেসগুলি পূর্বনির্ধারণ করে প্রতিটি উপাদান কীভাবে আচরণ করে তা কার্যকরভাবে পরীক্ষা করা সম্ভব (ইউনিট পরীক্ষার মাধ্যমে)
  • সিস্টেম সম্প্রসারণের সময় নতুন উপাদানগুলি অন্যের উপর বা অন্যের সাথে যুক্ত হতে পারে, উত্তরাধিকার বা রচনা দ্বারা

এই পর্যায়ে ব্যাকটেস্টারটি বাস্তবায়নের সহজতা এবং যুক্তিসঙ্গত স্তরের নমনীয়তার জন্য ডিজাইন করা হয়েছে, সত্যিকারের বাজারের নির্ভুলতার বিনিময়ে। বিশেষত, এই ব্যাকটেস্টারটি কেবলমাত্র একটি একক যন্ত্রের উপর কাজ করে এমন কৌশলগুলি পরিচালনা করতে সক্ষম হবে। পরে ব্যাকটেস্টারটি সরঞ্জামগুলির সেটগুলি পরিচালনা করতে সংশোধন করা হবে। প্রাথমিক ব্যাকটেস্টারের জন্য নিম্নলিখিত উপাদানগুলি প্রয়োজনঃ

  • কৌশল - একটি কৌশল শ্রেণী বারগুলির একটি পান্ডা ডেটাফ্রেম গ্রহণ করে, অর্থাৎ একটি নির্দিষ্ট ফ্রিকোয়েন্সিতে ওপেন-হাই-নিম্ন-ক্লোজ-ভলিউম (ওএইচএলসিভি) ডেটা পয়েন্টগুলির একটি তালিকা। কৌশলটি সংকেতগুলির একটি তালিকা তৈরি করবে, যার মধ্যে একটি টাইমস্ট্যাম্প এবং সেট থেকে একটি উপাদান রয়েছে {1,0,−1} যথাক্রমে একটি দীর্ঘ, হোল্ড বা সংক্ষিপ্ত সংকেত নির্দেশ করে।
  • পোর্টফোলিও - বেশিরভাগ ব্যাকটেস্টিং কাজ পোর্টফোলিও ক্লাসে ঘটবে। এটি সংকেতগুলির একটি সেট গ্রহণ করবে (যেমন উপরে বর্ণনা করা হয়েছে) এবং নগদ উপাদানটির বিরুদ্ধে বরাদ্দ করা একটি ধারাবাহিক অবস্থান তৈরি করবে। পোর্টফোলিও অবজেক্টের কাজ হ'ল একটি ইক্যুইটি বক্ররেখা তৈরি করা, মৌলিক লেনদেনের ব্যয় অন্তর্ভুক্ত করা এবং ব্যবসায়ের ট্র্যাক রাখা।
  • পারফরম্যান্স - পারফরম্যান্স অবজেক্ট একটি পোর্টফোলিও নেয় এবং তার পারফরম্যান্স সম্পর্কে পরিসংখ্যানের একটি সেট তৈরি করে। বিশেষত এটি ঝুঁকি / রিটার্ন বৈশিষ্ট্যগুলি (শার্প, সোর্টিনো এবং তথ্য অনুপাত), বাণিজ্য / মুনাফা পরিমাপ এবং ড্রডাউন তথ্য আউটপুট করবে।

কিসের অভাব?

যেমনটি দেখা যায়, এই ব্যাকটেস্টারটিতে পোর্টফোলিও / ঝুঁকি ব্যবস্থাপনা, এক্সিকিউশন হ্যান্ডলিং (যেমন কোনও সীমা অর্ডার নেই) এর কোনও উল্লেখ নেই এবং এটি লেনদেনের ব্যয়ের পরিশীলিত মডেলিং সরবরাহ করবে না। এটি এই পর্যায়ে খুব বেশি সমস্যা নয়। এটি আমাদের একটি অবজেক্ট-ভিত্তিক ব্যাকটেস্টার এবং পান্ডা / নুমপি লাইব্রেরি তৈরির প্রক্রিয়াটি সম্পর্কে পরিচিত হতে দেয়। সময়ের সাথে এটি উন্নত হবে।

বাস্তবায়ন

আমরা এখন প্রতিটি বস্তুর জন্য বাস্তবায়নগুলি রূপরেখা করতে এগিয়ে যাব।

কৌশল

কৌশল অবজেক্টটি এই পর্যায়ে মোটামুটি সাধারণ হতে হবে, কারণ এটি পূর্বাভাস, গড়-বিপরীতমুখী, গতি এবং অস্থিরতা কৌশলগুলি পরিচালনা করবে। এখানে বিবেচনা করা কৌশলগুলি সর্বদা সময় সিরিজ ভিত্তিক হবে, অর্থাৎ মূল্য চালিত। এই ব্যাকটেস্টারের জন্য একটি প্রাথমিক প্রয়োজনীয়তা হ'ল প্রাপ্ত কৌশল ক্লাসগুলি টিক (ট্রেড-বাই-ট্রেড দাম) বা অর্ডার-বুক ডেটা নয়, ইনপুট হিসাবে বারগুলির একটি তালিকা (ওএইচএলসিভি) গ্রহণ করবে। সুতরাং এখানে বিবেচনা করা সূক্ষ্মতম গ্রানুলারিটি 1 সেকেন্ডের বার হবে।

কৌশল ক্লাসটি সর্বদা সংকেত সুপারিশও তৈরি করবে। এর অর্থ এটি একটি পোর্টফোলিও ইনস্ট্যান্সকে দীর্ঘ / সংক্ষিপ্ত বা অবস্থান ধরে রাখার অর্থে পরামর্শ দেবে। এই নমনীয়তা আমাদের একাধিক কৌশল উপদেষ্টা তৈরি করতে দেয় যা সংকেতগুলির একটি সেট সরবরাহ করে, যা আরও উন্নত পোর্টফোলিও ক্লাসটি প্রকৃত অবস্থানগুলি নির্ধারণের জন্য গ্রহণ করতে পারে।

ক্লাসগুলির ইন্টারফেস একটি বিমূর্ত বেস ক্লাস পদ্ধতি ব্যবহার করে প্রয়োগ করা হবে। একটি বিমূর্ত বেস ক্লাস এমন একটি বস্তু যা ইনস্ট্যান্ট করা যায় না এবং এইভাবে কেবল উদ্ভূত ক্লাস তৈরি করা যায়। পাইথন কোডটি নীচে একটি ফাইল নামে দেওয়া হয়েছেbacktest.py. স্ট্র্যাটেজি ক্লাসের প্রয়োজন যে কোন উপশ্রেণীর জেনারেট_সিগন্যাল পদ্ধতি বাস্তবায়ন করা উচিত।

কৌশল শ্রেণীকে সরাসরি ইনস্ট্যান্ট করা থেকে বিরত রাখতে (যেহেতু এটি বিমূর্ত!), এটি ABCMeta এবং abstractmethod বস্তুগুলিকে abc মডিউল থেকে ব্যবহার করা প্রয়োজন। আমরা শ্রেণীর একটি বৈশিষ্ট্য সেট করি, যা বলা হয়মেটাক্লাস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()!")

যদিও উপরের ইন্টারফেসটি সহজ সরল তবে যখন এই ক্লাসটি প্রতিটি নির্দিষ্ট ধরণের কৌশলটির জন্য উত্তরাধিকার সূত্রে প্রাপ্ত হয় তখন এটি আরও জটিল হয়ে ওঠে। শেষ পর্যন্ত এই সেটিংসে কৌশল শ্রেণীর লক্ষ্য হ'ল পোর্টফোলিওতে প্রেরণ করা প্রতিটি যন্ত্রের জন্য দীর্ঘ / সংক্ষিপ্ত / হোল্ড সংকেতগুলির একটি তালিকা সরবরাহ করা।

পোর্টফোলিও

পোর্টফোলিও ক্লাস হল যেখানে বেশিরভাগ ট্রেডিং লজিক থাকবে। এই গবেষণার ব্যাকটেস্টের জন্য পোর্টফোলিও অবস্থান আকার নির্ধারণ, ঝুঁকি বিশ্লেষণ, লেনদেনের খরচ ব্যবস্থাপনা এবং সম্পাদন হ্যান্ডলিং (যেমন বাজারে খোলা, বাজারে বন্ধ আদেশ) নির্ধারণের জন্য দায়ী। পরবর্তী পর্যায়ে এই কাজগুলি পৃথক উপাদানগুলিতে বিভক্ত করা হবে। এখনই তারা একটি শ্রেণীতে ঘূর্ণিত হবে।

এই ক্লাসটি পান্ডা ব্যাপকভাবে ব্যবহার করে এবং লাইব্রেরিটি প্রচুর পরিমাণে সময় সাশ্রয় করতে পারে এমন একটি দুর্দান্ত উদাহরণ সরবরাহ করে, বিশেষত boilerplate ডেটা ঝগড়া সম্পর্কিত। একপাশে, পান্ডা এবং নুমপি এর প্রধান কৌশলটি হ'ল ফর ডি ইন... সিনট্যাক্স ব্যবহার করে কোনও ডেটাসেটের উপর পুনরাবৃত্তি এড়ানো। এটি কারণ নুমপি (যা পান্ডার অন্তর্নিহিত) ভেক্টরাইজড অপারেশন দ্বারা লুপিংকে অনুকূল করে তোলে। সুতরাং আপনি পান্ডা ব্যবহার করার সময় খুব কম (যদি থাকে) সরাসরি পুনরাবৃত্তি দেখতে পাবেন।

পোর্টফোলিও শ্রেণীর লক্ষ্য হল অবশেষে ট্রেডের একটি ক্রম এবং একটি ইক্যুইটি বক্ররেখা তৈরি করা, যা পারফরম্যান্স শ্রেণীর দ্বারা বিশ্লেষণ করা হবে। এটি অর্জনের জন্য এটিকে একটি কৌশল বস্তু থেকে ট্রেডিং সুপারিশগুলির একটি তালিকা সরবরাহ করতে হবে। পরে, এটি কৌশল বস্তুর একটি গ্রুপ হবে।

পোর্টফোলিও শ্রেণীকে বলা দরকার যে কীভাবে মূলধনটি একটি নির্দিষ্ট সেট ট্রেডিং সিগন্যালের জন্য মোতায়েন করা হবে, কীভাবে লেনদেনের ব্যয় পরিচালনা করা হবে এবং অর্ডারগুলির কোন ফর্মগুলি ব্যবহার করা হবে। কৌশল অবজেক্টটি ডেটা বারগুলিতে কাজ করছে এবং তাই অর্ডারের কার্যকরকরণের সময় প্রাপ্ত দামের বিষয়ে অনুমান করা উচিত। যেহেতু কোনও বারের উচ্চ / নিম্ন মূল্য অজানা a priori এটি কেবল ট্রেডিংয়ের জন্য খোলা এবং বন্ধের দাম ব্যবহার করা সম্ভব। বাস্তবে এটি অসম্ভব যে কোনও অর্ডার এই নির্দিষ্ট দামগুলির মধ্যে একটিতে পূরণ হবে তা গ্যারান্টি দেওয়া সম্ভব নয় যখন বাজার অর্ডার ব্যবহার করা হয়, তাই এটি সর্বোত্তম ক্ষেত্রে, একটি আনুমানিক হবে।

অর্ডার পূরণ সম্পর্কে অনুমানের পাশাপাশি, এই ব্যাকটেস্টার মার্জিন / ব্রোকারেজ সীমাবদ্ধতার সমস্ত ধারণাগুলি উপেক্ষা করবে এবং অনুমান করবে যে কোনও যন্ত্রের কোনও তরলতার সীমাবদ্ধতা ছাড়াই অবাধে দীর্ঘ এবং সংক্ষিপ্ত যেতে পারে। এটি স্পষ্টতই একটি খুব অবাস্তব অনুমান, তবে এটি পরে শিথিল করা যেতে পারে।

নিম্নলিখিত তালিকাটি অব্যাহত রয়েছে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

এই ক্ষেত্রে কৌশলটি অর্থ হারিয়েছে, যা পূর্বাভাসদাতার স্টোকাস্টিক প্রকৃতি দেওয়া অবাক হওয়ার মতো নয়! পরবর্তী পদক্ষেপগুলি একটি পারফরম্যান্স অবজেক্ট তৈরি করা যা একটি পোর্টফোলিও উদাহরণ গ্রহণ করে এবং পারফরম্যান্স মেট্রিকগুলির একটি তালিকা সরবরাহ করে যার উপর ভিত্তি করে কৌশলটি ফিল্টার করার সিদ্ধান্ত নেওয়া বা না করা।

আমরা লেনদেনের খরচ (যেমন ইন্টারেক্টিভ ব্রোকার কমিশন এবং স্লিপজ) আরও বাস্তবসম্মত হ্যান্ডলিং করার জন্য পোর্টফোলিও অবজেক্টটিও উন্নত করতে পারি। আমরা সহজেই একটি পূর্বাভাস ইঞ্জিনকে একটি কৌশল অবজেক্টে অন্তর্ভুক্ত করতে পারি, যা (আশা করি) আরও ভাল ফলাফল দেবে। পরবর্তী নিবন্ধগুলিতে আমরা এই ধারণাগুলি আরও গভীরভাবে অনুসন্ধান করব।


আরো