Colab - mass screen backtest

I have previously mentioned that I would like to test a large quantity of ranking systems (2000). Up to now, I have been doing this using rolling backtests in Dataminer, but there are some weaknesses in conducting such tests with rolling backtests instead of screen backtests or simulators.

Can this code be repeated so that I can test a large number of ranking systems with this code, with some kind of repeater?


try:
    client = p123api.Client(api_id='xx', api_key='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')  #Your ID and Key

    print(client.screen_backtest(
        {
            'screen': {
                'type': 'stock',          #Stock or ETF
        'universe': '1. Pareto - US CANADA volumfilter',
        'maxNumHoldings': 25,  #0 for all
        'method': 'long' | 'short' | 'long/short' | 'hedged',
        'currency': 'USD' | 'CAD' | 'CHF' | 'EUR' | 'GBP' | 'NOK' | 'PLN' | 'SEK' | 'TRY',
        'benchmark': 'iwm',
        #Several options for specifying the ranking. Choose one of these 5:
        'ranking': '120224+beste+ri',
        'startDt': '2010-01-01',
        'endDt': '2024-05-30',
        'pitMethod': 'Prelim',       #Prelim or Complet
        'precision': 2,              #2,3,4
        'transPrice': 3,             #1 - Next Open, 4 - Next Close, 3 - Next Average of Hi and Low
        'slippage': 0.25,
        'longWeight': 100,
        'rankTolerance': 5,
        'rebalFreq': 'Every Week' | 'Every Week' | 
        'riskStatsPeriod': "Monthly"  #Monthly, Weekly, Daily
        }
        ))
except p123api.ClientException as e:
    print(e)

Maybe Im answering my own question.

But with something like this: "rankings = ['ranking1', 'ranking2', 'ranking3', 'ranking4', ..., 'ranking500'] #"

import p123api

try:
    client = p123api.Client(api_id='xx', api_key='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')  # Your ID and Key

    rankings = [
        "Optimize System - Copy(2078)190424udob300n-40-48",
        "Optimize System - Copy(2078)190424udob300n-40-47",
        "Optimize System - Copy(2078)190424udob300n-40-46",
        "Optimize System - Copy(2078)190424udob300n-40-45",
        "Optimize System - Copy(2078)190424udob300n-40-44",
        "Optimize System - Copy(2078)190424udob300n-40-43",
        "Optimize System - Copy(2078)190424udob300n-40-42",
        "Optimize System - Copy(2078)190424udob300n-40-41",
        "Optimize System - Copy(2078)190424udob300n-40-40",
        "Optimize System - Copy(2078)190424udob300n-40-39",
        "Optimize System - Copy(2078)190424udob300n-40-38",
        "Optimize System - Copy(2078)190424udob300n-40-37",
        "Optimize System - Copy(2078)190424udob300n-40-36",
        "Optimize System - Copy(2078)190424udob300n-40-35",
        "Optimize System - Copy(2078)190424udob300n-40-34",
        "Optimize System - Copy(2078)190424udob300n-40-33",
        "Optimize System - Copy(2078)190424udob300n-40-32",
        "Optimize System - Copy(2078)190424udob300n-40-31",
        "Optimize System - Copy(2078)190424udob300n-40-30",
        "Optimize System - Copy(2078)190424udob300n-40-29",
        "Optimize System - Copy(2078)190424udob300n-40-28",
        "Optimize System - Copy(2078)190424udob300n-40-27",
        "Optimize System - Copy(2078)190424udob300n-40-26",
        "Optimize System - Copy(2078)190424udob300n-40-25",
        "Optimize System - Copy(2078)190424udob300n-40-24",
        "Optimize System - Copy(2078)190424udob300n-40-23",
        "Optimize System - Copy(2078)190424udob300n-40-22",
        "Optimize System - Copy(2078)190424udob300n-40-21",
        "Optimize System - Copy(2078)190424udob300n-40-20",
        "Optimize System - Copy(2078)190424udob300n-40-19",
        "Optimize System - Copy(2078)190424udob300n-40-18",
        "Optimize System - Copy(2078)190424udob300n-40-17",
        "Optimize System - Copy(2078)190424udob300n-40-16",
        "Optimize System - Copy(2078)190424udob300n-40-15",
        "Optimize System - Copy(2078)190424udob300n-40-14",
        "Optimize System - Copy(2078)190424udob300n-40-13",
        "Optimize System - Copy(2078)190424udob300n-40-12",
        "Optimize System - Copy(2078)190424udob300n-40-11",
        "Optimize System - Copy(2078)190424udob300n-40-10",
        "Optimize System - Copy(2078)190424udob300n-40-9",
        "Optimize System - Copy(2078)190424udob300n-40-8",
        "Optimize System - Copy(2078)190424udob300n-40-7",
        "Optimize System - Copy(2078)190424udob300n-40-6",
        "Optimize System - Copy(2078)190424udob300n-40-5",
        "Optimize System - Copy(2078)190424udob300n-40-4",
        "Optimize System - Copy(2078)190424udob300n-40-3",
        "Optimize System - Copy(2078)190424udob300n-40-2",
        "Optimize System - Copy(2078)190424udob300n-40-1",
        "Optimize System - Copy(2078)190424udob300n-39-50",
        "Optimize System - Copy(2078)190424udob300n-39-49",
        "Optimize System - Copy(2078)190424udob300n-39-48",
        "Optimize System - Copy(2078)190424udob300n-39-47",
        "Optimize System - Copy(2078)190424udob300n-39-46",
        "Optimize System - Copy(2078)190424udob300n-39-45",
        "Optimize System - Copy(2078)190424udob300n-39-44",
        "Optimize System - Copy(2078)190424udob300n-39-43",
        "Optimize System - Copy(2078)190424udob300n-39-42",
        "Optimize System - Copy(2078)190424udob300n-39-41",
        "Optimize System - Copy(2078)190424udob300n-39-40",
        "Optimize System - Copy(2078)190424udob300n-39-39"
    ]  # Liste med dine rankingsystemer

    for ranking in rankings:
        result = client.screen_backtest(
            {
                'screen': {
                    'type': 'stock',  # Stock or ETF
                    'universe': '1. Pareto - US CANADA volumfilter',
                    'maxNumHoldings': 25,  # 0 for all
                    'method': 'long',  # long, short, long/short, hedged
                    'currency': 'USD',  # USD, CAD, CHF, EUR, GBP, NOK, PLN, SEK, TRY
                    'benchmark': 'iwm',
                    'ranking': ranking,
                    'startDt': '2010-01-01',
                    'endDt': '2024-05-30',
                    'pitMethod': 'Prelim',  # Prelim or Complet
                    'precision': 2,  # 2, 3, 4
                    'transPrice': 3,  # 1 - Next Open, 4 - Next Close, 3 - Next Average of Hi and Low
                    'slippage': 0.25,
                    'longWeight': 100,
                    'rankTolerance': 5,
                    'rebalFreq': 'Every Week',  # Every Week, Every Month
                    'riskStatsPeriod': "Monthly"  # Monthly, Weekly, Daily
                }
            })
        print(f"Ranking: {ranking}\nResult: {result}\n")
except p123api.ClientException as e:
    print(e)

This work:

  • Import necessary libraries:
  • p123api
  • pandas
  • time
  • Read rankings from a CSV file:
  • Attempt to read the file 'C:\\Users\\xxx\\Documents\\YT\\rankings.csv'.
  • Check if the 'ranking' column exists.
  • If the file or column is missing, print an error message and set rankings to an empty list.
  • If the column exists, create a list of rankings.
  • Initialize the Portfolio123 API client:
  • Create a p123api.Client object with the API ID and key if rankings is not empty.
  • Perform backtest for each ranking:
  • For each ranking in rankings:
    • Perform a backtest with specified parameters using client.screen_backtest.
    • Handle API request failures with retries and delays.
  • Process and save results:
  • Flatten the backtest results and add them to all_data.
  • Convert results to a DataFrame and print them.
  • Save the final DataFrame to 'rankings_results.csv'.

Also with a time.sleep(10), on the API request.

import pandas as pd
import time

# Read rankings from CSV file
try:
    rankings_df = pd.read_csv('C:\\Users\\mywag\\Documents\\YT\\rankings.csv', sep=',')
    if 'ranking' not in rankings_df.columns:
        raise KeyError("The column 'ranking' does not exist in the CSV file.")
    rankings = rankings_df['ranking'].tolist()  # Assuming the CSV has a column named 'ranking'
except FileNotFoundError:
    print("The specified CSV file was not found.")
    rankings = []
except KeyError as e:
    print(e)
    rankings = []

if rankings:
    try:
        client = p123api.Client(api_id='XXX', api_key='XXX')  # Your ID and Key
        all_data = []
        first_print = True

        for ranking in rankings:
            success = False
            while not success:
                try:
                    result = client.screen_backtest(
                        {
                            'startDt': "2014-01-01",
                            'endDt': "2024-06-30",
                            'pitMethod': 'Prelim',  # Prelim or Complete
                            'precision': 2,  # 2, 3, 4
                            'transPrice': 3,  # 1 - Next Open, 4 - Next Close, 3 - Next Average of Hi and Low
                            'slippage': 0.1,
                            'longWeight': 100,
                            'rankTolerance': 1,
                            'rebalFreq': 'Every Week',  # Every Week, Every Month
                            'riskStatsPeriod': "Monthly",  # Monthly, Weekly, Daily
                            'screen': {
                                'type': 'stock',  # Stock or ETF
                                'universe': '1. Pareto - US CANADA volumfilter',
                                'maxNumHoldings': 25,  # 0 for all
                                'method': 'long',  # long, short, long/short, hedged
                                'currency': 'USD',  # USD, CAD, CHF, EUR, GBP, NOK, PLN, SEK, TRY
                                'benchmark': 'iwm',
                                'ranking': ranking,
                                'rules': []
                            }
                        })

                    stats = result['stats']

                    # Flatten the nested dictionary for easier display in a single row
                    flattened_stats = {'Ranking': ranking}
                    for key, value in stats.items():
                        if isinstance(value, dict):
                            for sub_key, sub_value in value.items():
                                flattened_stats[f"{key}_{sub_key}"] = sub_value
                        else:
                            flattened_stats[key] = value

                    all_data.append(flattened_stats)

                    # Convert to DataFrame and print with commas
                    df = pd.DataFrame([flattened_stats])
                    if first_print:
                        print(','.join(df.columns))
                        first_print = False
                    print(df.to_csv(index=False, header=False).strip())
                    
                    success = True  # Set success to True if request was successful

                except p123api.ClientException as e:
                    print(f"API request failed: {e}")
                    time.sleep(10)  # Wait for 10 seconds before retrying

        # Create final DataFrame and save to CSV
        final_df = pd.DataFrame(all_data)
        final_df.to_csv('rankings_results.csv', index=False)

    except p123api.ClientException as e:
        print(e)