ドキュメント

アプリケーション

最終更新日: 2022年7月21日(マーク・フリック)

複数の結果をポートフォリオに統合する

この記事では、StrategyQuant Xがバックテストの結果をどのように処理するか、またそれらをポートフォリオに統合する方法について解説します。.

これはSQXで複数の戦略を選択し、選択することで、すでに実行可能です。 ポートフォリオ → マージ戦略, しかし、その裏側がどのように処理されているかをお見せします。.

これは複数回にわたるシリーズの第1弾として意図されており、特定の戦略のサブセットを選択してトレードすることで改善できるかどうかをこの機能を使って検証していきたいと考えています。これは今後の記事で検討される予定です。.

 

ポートフォリオへの統合とは、個々のトレーディング戦略を統合することではなく、最終的なバックテスト結果を1つのポートフォリオ結果に統合することを意味する点に注意してください。.

 

この機能もカスタム分析スニペットの形式で作成されており、完全なスニペットがこの記事に添付されています。.

 

バックテスト結果の操作 – ResultsGroupオブジェクト

念のためお伝えしておきますが、SQXでは、すべてのバックテスト結果はResultオブジェクトに格納され、それらはResultsGroupオブジェクトにグループ化されます。.

RegultGroupとはデータバンクに表示されるもので、メイン市場や追加市場などでの戦略のバックテストである1つ以上の結果を含むことができます。.

以下の紹介文付きの記事があります: ResultsGroup の操作

 

複数の戦略の結果を1つのポートフォリオに統合したい場合、私たちは

  • ポートフォリオを保持する新しいResultsGroupオブジェクトを作成する
  • データバンク内のすべての戦略のResultsGroupオブジェクトを処理する
  • メインデータに対するバックテストが含まれている主な結果を見つけてください。これが今回マージするものです。
  • このストラテジー用の新しいResultオブジェクトを作成し、ポートフォリオに追加する。
  • 元のResultsGroupから注文をポートフォリオに複製およびコピーする
  • 元のResultsGroupからポートフォリオにシンボルをコピーする - これは損益(PL)などの計算に必要です。.
  • 最後に、新しいポートフォリオの結果を作成し、すべての統計を計算します。

 

 

スニペットの完全なソースコード

コードには詳細なコメントがついているので、そのロジックをたどることができます。.

これにより、2つの新しいポートフォリオ結果が作成されます。1つは私たちが手動で作成したもので、もう1つは比較のためにSQXメソッドによって作成されたものです。.

 

package SQ.CustomAnalysis;

import com.strategyquant.lib.SQUtils;
import com.strategyquant.lib.SettingsMap;
import com.strategyquant.lib.utils.IUniqueNameChecker;
import com.strategyquant.tradinglib.*;
import com.strategyquant.tradinglib.project.ProjectEngine;
import com.strategyquant.tradinglib.results.SpecialValues;
import com.strategyquant.tradinglib.results.stats.comparator.OrderComparatorByOpenTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;

public class CAMergeStrategiesToPortfolio extends CustomAnalysisMethod {
    public static final Logger Log = LoggerFactory.getLogger("CAMergeStrategiesToPortfolio");

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------

    public CAMergeStrategiesToPortfolio() {
        super("Merge Strategies To Portfolio", TYPE_PROCESS_DATABANK);
    }

    //------------------------------------------------------------------------

    @Override
    public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        return false;
    }


    //------------------------------------------------------------------------

    @Override
    public ArrayList<ResultsGroup> processDatabank(String project, String task, String databankName, ArrayList<ResultsGroup> databankRG) throws Exception {
        if(databankRG.size() <= 1) {
            // if there is no or just one strategy there is nothing to merge
            return databankRG;
        }

        // get target databank to save the final result
        Databank targetDatabank = ProjectEngine.get(project).getDatabanks().get("Portfolios");
        if(targetDatabank == null) {
            throw new Exception("Please create a new databank named 'Portfolios' !");
        }

        // ------------------------------
        // Creating portfolio manually


        // merge all strategies in databank to one portfolio
        ResultsGroup caPortfolio = mergeStrategiesToPortfolio(databankRG);

        // create final Portfolio result to sum all sub-results
        createPortfolioResult(caPortfolio);

        // add new portfolio to our target databank
        targetDatabank.add(caPortfolio, false);


        // ------------------------------
        // Creating portfolio in a standard way by calling SQ method - for control
        ResultsGroup standardPortfolio = ResultsGroup.merge(databankRG, new String[] { ResultsGroup.AdditionalMarket }, null);

        standardPortfolio.createPortfolioResult(PortfolioInitialBalanceTypes.SINGLE, null);

        targetDatabank.add(standardPortfolio, false);

        return databankRG;
    }

    //------------------------------------------------------------------------

    private ResultsGroup mergeStrategiesToPortfolio(ArrayList<ResultsGroup> databankRG) throws Exception {
        ResultsGroup caPortfolio = new ResultsGroup("PortfolioMadeByCA");

        // add individual strategies to portfolio
        for(ResultsGroup rg : databankRG) {
            addResult(caPortfolio, rg);
        }

        addSymbolsMap(caPortfolio, databankRG);

        return caPortfolio;
    }

    //------------------------------------------------------------------------

    private void addSymbolsMap(ResultsGroup rgCSPortfolio, ArrayList<ResultsGroup> databankRG) {
        for(ResultsGroup rg : databankRG) {
            // add all symbols from merged RGs to portfolio symbols map
            rgCSPortfolio.symbols().add(rg.symbols());
        }
    }

    //------------------------------------------------------------------------

    private void addResult(ResultsGroup caPortfolio, ResultsGroup rg) throws Exception {

        // first create a new result for RG in our new portfolio
        // newResultKey will be returned as its result key used in our portfolio
        String newResultKey = mergeResult(caPortfolio, rg);

        // next clone & copy orders for this results from RG to portfolio
        copyOrdersToPortfolio(caPortfolio, rg, newResultKey);

        // add all symbol data from merged RG to portfolio symbols map - this is necessary for computation of PL etc.
        caPortfolio.symbols().add(rg.symbols());
    }

    //------------------------------------------------------------------------

    private String mergeResult(ResultsGroup caPortfolio, ResultsGroup rg) throws Exception {
        // get main result from current strategy - this is the one we'll be merging
        Result rgMainResult = rg.mainResult();
        String mainResultKey = rgMainResult.getResultKey();

        // determine new result key - it must be unique so we have to check
        // if there isn't result with this key already in our portfolio
        String newResultKey = rg.getName();

        if(caPortfolio.hasResult(newResultKey)) {
            // same key already exists, we have to find a new key
            newResultKey = SQUtils.generateUniqueName(mainResultKey, new IUniqueNameChecker() {
                public boolean checkNameExist(String name) throws Exception {
                    return caPortfolio.hasResult(name);
                }
            });
        }

        // create merged result
        SettingsMap copiedSettingsMap = rgMainResult.getSettings().clone();

        // create new merged result ad add it to our portfolio
        Result mergedResult = new Result(newResultKey, caPortfolio, copiedSettingsMap);
        caPortfolio.addSubresult(newResultKey, copiedSettingsMap, mergedResult);

        // set symbol and timeframe from merged strategy
        mergedResult.setString(SpecialValues.Symbol, rg.mainResult().getString(SpecialValues.Symbol));
        mergedResult.setString(SpecialValues.Timeframe, rg.mainResult().getString(SpecialValues.Timeframe));

        long rgDateFrom = rg.specialValues().getLong(SpecialValues.HistoryFrom, Long.MAX_VALUE);
        long rgDateTo = rg.specialValues().getLong(SpecialValues.HistoryTo, Long.MIN_VALUE);

        long caDateFrom = caPortfolio.specialValues().getLong(SpecialValues.PortfolioHistoryFrom, Long.MAX_VALUE);
        long caDateTo = caPortfolio.specialValues().getLong(SpecialValues.PortfolioHistoryTo, Long.MIN_VALUE);

        caPortfolio.specialValues().set(SpecialValues.HistoryFrom, Math.min(rgDateFrom, caDateFrom));
        caPortfolio.specialValues().set(SpecialValues.HistoryTo, Math.max(rgDateTo, caDateTo));
        copiedSettingsMap.set(SettingsKeys.PortfolioDataStart, Math.min(rgDateFrom, caDateFrom));
        copiedSettingsMap.set(SettingsKeys.PortfolioDataEnd, Math.max(rgDateTo, caDateTo));

        return newResultKey;
    }

    //------------------------------------------------------------------------

    private void copyOrdersToPortfolio(ResultsGroup caPortfolio, ResultsGroup rg, String newResultKey) throws Exception {
        // get orders list from our current portfolio
        OrdersList mergedOrdersList = caPortfolio.orders();

        // get all orders from merging strategy result - note that they must be cloned!
        String mainResultKey = rg.mainResult().getResultKey();
        OrdersList filteredOL = rg.orders().filterWithClone(mainResultKey, Directions.Both, SampleTypes.FullSample);

        // no go through these orders and add them to portfolio orders list
        for(int i=0; i<filteredOL.size(); i++) {
            Order order = filteredOL.get(i);

            // order.SetupName is used as identifier so that we know to which result the order belongs to
            // so we have to set it to newResultKey
            order.SetupName = newResultKey;

            mergedOrdersList.add(order);
        }
    }

    //------------------------------------------------------------------------

    private void createPortfolioResult(ResultsGroup caPortfolio) throws Exception {

        SettingsMap settings = caPortfolio.mainResult().getSettings();

        Result portfolioResult = new Result(ResultsGroup.Portfolio, caPortfolio, settings);

        caPortfolio.removeSubresult(ResultsGroup.Portfolio, true);

        caPortfolio.addSubresult(ResultsGroup.Portfolio, settings, portfolioResult);

        caPortfolio.specialValues().setString(SpecialValues.Symbol, ResultsGroup.Portfolio);

        // for portfolio sort orders by their open time
        OrdersList ordersList = caPortfolio.orders();
        ordersList.sort(new OrderComparatorByOpenTime());

        portfolioResult.computeAllStats(caPortfolio.specialValues(), caPortfolio.getOOS());

        caPortfolio.updated = true;
    }

}

 

この記事は参考になりましたか? この記事は役に立った この記事は役に立たなかった

1 コメント
最古の
最新 最も投票された
エマニュエル
2022年7月21日 午後12:14

素晴らしい例!!まさに私が必要としていたものです!!マーク、ありがとう

関連記事