The API Wrapper - p123api

Describes the p123api package with objects and functions that facilitate using the P123 API

Introduction

To facilitate using the our Rest API we created a python package that wraps the API endpoints. The package is called p123api and it makes it very easy to start using the API. It handles several things like retries, authentication and low level http request.

The wrapper is an open source project and is hosted at pypi.org. The package is still being developed, let us know of any issues or inconsistencies. For an example using the p123api in a Google Colab notebook see this article.

To use p123api you can start your code like this:

# Install p123api if missing
!pip install --upgrade p123api

import p123api

try:
    client = p123api.Client(api_id='YOUR_API_ID', api_key='YOUR_API_KEY_XXXX')  
    
    # call package function(s)
    res1 = client.p123api_function1()

    ... etc ...

except p123api.ClientException as e:
    print(e)

Functions

Each API endpoint has been wrapped with a function. They are listed below grouped the same way as the API reference. The parameters for the functions should be identical to the API specification, but some inconsistencies do exist. Lastly, for optional parameter the default value when not specified is the first value in the list (if any).

Data Functions

data()

Wrapper for POST/data

This operation allows you to retrieve large sets of data from our point in time engine. You will need to obtain your own license from the data vendor (Factset or Compustat) to fully access. You can try it without a license with the following stocks: IBM, MSFT & INTC and for 5 years of history.

p123api.Client().data({
    # Specify either: tickers, cusips, p123Uids, ciks, 
    # or gvkeys (Compustat only)
    'tickers': ['ticker1', 'ticker2'' ...],
    'formulas': ['form1', 'form2', ... ],
    'startDt': 'yyyy-mm-dd',
    'endDt': 'yyyy-mm-dd',
    # optional parameters
    'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF',
    'precision': 2 | 3 | 4,
    'frequency': 'Every Week' | 'Every N Weeks' (2,3,4,6,8,13,26,52),
    'pitMethod': 'Prelim' | 'Complete',
    'includeNames': True | False,
    'region': 'United States' | 'Canada' | 'North America',
    'ignoreErrors': True | False
},True) # True - output to Pandas DataFrame | [False] to JSON.

data_universe()

Wrapper for POST​/data​/universe

This operation allows you to retrieve point in time data for a selected universe. A data license with the data providers we support (Compustat or Factset) is required for this operation in order to return fundamental factors. However, you can retrieve most price related data and derived fundamental factor ranks and z-scores without a vendor data license. An example of derived data would be the Price to Sales rank vs the other stocks in the stocks industry.

p123api.Client().data_universe({
    # Specify the universe name (ex 'SP500'). To use the 
    # API universe that can be updated with other
    # API functions use 'APIUniverse' 
    'universe': 'Universe name',
    'asOfDt': 'yyyy-mm-dd',
    'formulas': ['form1', 'form2', ... ],
    # optional parameters
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'includeNames': False,
    'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF'
},True) # True - output to Pandas DataFrame | [False] to JSON.

Universe Functions

universe_update()

Wrapper for POST​/universe

This operation updates the Universe used by API. This universe is always called "ApiUniverse" and it's stored in your account. If you don’t have this Universe already saved in the platform, it will be created.

p123api.Client().universe_update( {
    'rules': ['rule1','rule2', ... ],
    # optional parameters
    'type': 'stock' | 'etf', 
    'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF',
    'startingUniverse': 'SP500' (optional)
})

Rank Functions

rank_ranks()

Wrapper for POST​/rank​/ranks

This operation allows you to retrieve rank data from a ranking system for a specific universe.

p123api.Client().rank_ranks({
    'rankingSystem': 'Ranking name',
    'asOfDt': 'yyyy-mm-dd',
    'universe': 'Universe name',
    #
    # Optional parameters,
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'rankingMethod': 2, # 2-Percentile NAs Negative, 4-Percentile NAs Neutral
    # Filter for specific stocks
    'tickers': 'IBM,MSFT',
    'includeNames': False,
    'includeNaCnt': False,
    'includeFinalStmt': False,
    'nodeDetails': 'composite' | 'factor',
    'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF',
    'additionalData': ['formula1','formula2',...]
     # Example: ['Close(0)', 'mktcap', "ZScore(`Pr2SalesQ`,#All)"]
},True) # True - output to Pandas DataFrame | [False] to JSON.

rank_perf()

Wrapper for POST​/rank​/performance

This operation lets you run multiple bucket performance tests of multifactor ranking systems. You can specify the system directly as well as use one of your existing ones. Other specific settings include the number of buckets, minimum price, transaction slippage (expressed in %), sector, benchmark and output type. The output includes many more statistics than what the website offers (to collect these stats the API runs a screen backtest for each bucket).

p123api.Client().rank_perf({
    'rankingSystem': 'Rank Name',
    'startDt': 'yyyy-mm-dd',
    #
    # Optional parameters
    'endDt': 'yyyy-mm-dd',
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'universe': 'Universe name',
    'transType': 'Long' | 'Short',
    'rankingMethod': 2, # 2 NAs Negative | 4 NAs Neutral
    'numBuckets': 10,
    'minPrice': 5,
    'rebalFreq': 'Every 4 Weeks' | 'Every Week' | 
                 'Every N Weeks' (2,3,4,6,8,13,26,52),
    'slippage': 0,
    'benchmark': 'SPY',
    'outputType': 'ann' | 'perf'
})

rank_update()

Wrapper for POST​/rank

This operation updates the "API ranking system" called ApiRankingSystem. If you don’t have this ranking system already saved in the platform, it will be created.

p123api.Client().rank_update({
    'nodes': 'node definition',
    'type': 'stock' | 'etf',
    #
    # Optional parameters
    'rankingMethod': 2,  # 2 NAs Negative, 4 NAs Neutral
    'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF'
})

Screen Functions

screen_run()

Wrapper for POST​/screen​/run

This operation allows you to run a screen. You can specify the screen settings directly as well as use one of your existing screens.

# Specify the screen settings inline:
p123api.Client().screen_run({
    'screen': {
        'type': 'stock' | 'etf',
        'universe': 'Universe name',
        'maxNumHoldings': 10, # 0 for all
        'method': 'long' | 'short' | 'long/short' | 'hedged',
        'benchmark': 'SPY',
        'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF',

        #Several options for specifying the ranking. Choose one of these 5:
        'ranking': 'Ranking Name',
        'ranking': id,
        'ranking': {
            'method': 0, # 0-Use Ranking System Default, 2-Percentile NAs Negative, 
                         # 4-Percentile NAs Neutral, 1-Normal Distribution
            'id': id},
        'ranking': {
            'method': 0,
            'name': 'Ranking Name'},
        'ranking': {
            'formula': 'formula1',
            'lowerIsBetter': True | False },

        'rules': [
            {'formula': 'formula1',
                'type': 'common' | 'long' | 'short' | 'hedge'
            },
            {'formula': 'formula2',
                'type': 'common' | 'long' | 'short' | 'hedge'
            }
            ... etc ...]
    'asOfDt': 'yyyy-mm-dd',
    #
    # Optional parameters
    'pitMethod': 'Prelim' | 'Complete'
    'precision': 2 | 3 | 4,
    },True) # True - output to Pandas DataFrame | [False] to JSON.
# Run an existing screen using the integer id of the screen:
p123api.Client().client.screen_run({
    'screen': id,
    'asOfDt': 'yyyy-mm-dd',
    #
    # Optional parameters
    'pitMethod': 'Prelim' | 'Complete'
    'precision': 2 | 3 | 4,
    },True) # True - output to Pandas DataFrame | [False] to JSON.
# Run an existing screen using the integer id of the screen and maxNumHoldings:
p123api.Client().client.screen_run({
    'screen': {
        'id': id,
        'maxNumHoldings': 10  # 0 for all. Optional.
        },
    'asOfDt': 'yyyy-mm-dd',
    #
    # Optional parameters
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4
    },True) # True - output to Pandas DataFrame | [False] to JSON.

screen_backtest()

Wrapper for POST​/screen​/backtest

This operation allows you to run a performance backtest of a Screen.

# Backtest a screen which is defined inline:
p123api.Client().screen_backtest({
    'screen': {
        'type': 'stock' | 'etf',
        'universe': 'Universe name',
        'maxNumHoldings': 10,  #0 for all
        'method': 'long' | 'short' | 'long/short' | 'hedged',
        'currency': 'USD' | 'CAD' | 'EUR' | 'GBP' | 'CHF',
        'benchmark': 'SPY',

        #Several options for specifying the ranking. Choose one of these 5:
        'ranking': 'Ranking Name',
        'ranking': id,
        'ranking': {
            'method': 0, # 0-Use Ranking System Default, 2-Percentile NAs Negative, 
                         # 4-Percentile NAs Neutral, 1-Normal Distribution
            'id': id},
        'ranking': {
            'method': 0,
            'name': 'Ranking Name'},
        'ranking': {
            'formula': 'formula1',
            'lowerIsBetter': True | False },

        'rules': [
            {'formula': 'formula1',
                'type': 'common' | 'long' | 'short' | 'hedge'
            },
            {'formula': 'formula2',
                'type': 'common' | 'long' | 'short' | 'hedge'
            }
            ... etc ...]
        },
    'startDt': '2020-01-01',
    #
    # Optional parameters
    'endDt': 'yyyy-mm-yy',
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'transPrice': 1, # 1 - Open | 3 - Avg of Hi and Low | 4 - Close
    'maxPosPct': 0,
    'slippage': 0.25,
    'longWeight': 100,
    'shortWeight': 100,
    'rankTolerance': 0,
    'carryCost': 0,
    'rebalFreq': 'Every 4 Weeks' | 'Every Week' | 
                 'Every N Weeks' (2,3,4,6,8,13,26,52),
    'riskStatsPeriod': ['Monthly'] | 'Weekly' | 'Daily'
    },True) # True - output to Pandas DataFrame | [False] to JSON.
# Backtest and existing screen using the integer id of the screen:
p123api.Client().screen_backtest({
    'screen': id,
    'startDt': '2020-01-01',
    #
    # Optional parameters
    'endDt': 'yyyy-mm-yy',
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'transPrice': 1, # 1 - Open | 3 - Avg of Hi and Low | 4 - Close
    'maxPosPct': 0,
    'slippage': 0.25,
    'longWeight': 100,
    'shortWeight': 100,
    'rankTolerance': 0,
    'carryCost': 0,
    'rebalFreq': 'Every 4 Weeks' | 'Every Week' | 
                 'Every N Weeks' (2,3,4,6,8,13,26,52),
    'riskStatsPeriod': 'Monthly' | 'Weekly' | 'Daily'
    },True) # True - output to Pandas DataFrame | [False] to JSON.
# Backtest an existing screen using the integer id of the screen and maxNumHoldings:
p123api.Client().screen_backtest({
    'screen': {
        'id': id,
        'maxNumHoldings': 10  # 0 for all. Optional.
        },
    'startDt': '2020-01-01',
    #
    # Optional parameters
    'endDt': 'yyyy-mm-dd',
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'transPrice': 1, # 1 - Open | 3 - Avg of Hi and Low | 4 - Close
    'maxPosPct': 0,
    'slippage': 0.25,
    'longWeight': 100,
    'shortWeight': 100,
    'rankTolerance': 0,
    'carryCost': 0,
    'rebalFreq': 'Every 4 Weeks' | 'Every Week' | 
                 'Every N Weeks' (2,3,4,6,8,13,26,52),
    'riskStatsPeriod': ['Monthly'] | 'Weekly' | 'Daily'
    },True) # True - output to Pandas DataFrame | [False] to JSON.

screen_rolling_backtest()

Wrapper for POST​/screen​/rolling-backtest

This operation allows you to run and collect the output of rolling screens. Rolling screens are subsequent, fixed holding period backtests of a screen, moving forward the starting date for each test. Rolling screens are excellent robustness tests.

p123api.Client().screen_rolling_backtest({
    'screen': id,
    'startDt': 'yyyy-mm-dd',
    #
    # Optional parameters
    'endDt': 'yyyy-mm-dd',
    'pitMethod': 'Prelim' | 'Complete',
    'precision': 2 | 3 | 4,
    'transPrice': 1, # 1 - Open | 3 - Avg of Hi and Low | 4 - Close
    'maxPosPct': 0,
    'slippage': 0.25,
    'longWeight': 100,
    'shortWeight': 100,
    'frequency': 'Every 4 Weeks' | 'Every Week',
    'holdingPeriod': 182
})

Strategy Functions

strategy()

Wrapper for GET​/strategy​/{id}

This operation returns the data from the Summary, Current Holdings and Statistics tabs of a strategies or books. The only parameter is the id of the strategy or book.

p123api.Client().strategy(
    strategy_id=id
)

Data Series Functions

You can create and store a custom data series which consists of a list of dates and their associated values. You can then use these series in your rules as explained here . There are 3 operations to create or update, delete or upload data to a custom data series.

data_series_create_update()

Wrapper for POST​ /dataSeries

Create or update a data series. To create a new series omit the id parameter. The id of the newly created series is returned.

p123api.Client().data_series_create_update({
    name : 'Name of Series',
    # ID of the data series to update, omit to create new one
    id : N,
    # optional parameters
    description : 'Series description optional'
})

data_series_delete()

Wrapper for DELETE​ /dataSeries/{id}

Deletes a data series and the data associated with it.

p123api.Client().data_series_delete(
    series_id = N
)

data_series_upload()

Wrapper for POST ​/dataSeries​/upload​/{id}

Upload the series data. Data must be tabular with date and value in each row.

p123api.Client().data_series_upload(
    file = 'C:/MyPath/SeriesData.csv',
    series_id = id of series,
    #
    # Optional parameters
    existing_data = 'overwrite' | 'skip' | 'delete',
    date_format = 'yyyy-mm-dd' | 'yyyy/mm/dd' | 'mm/dd/yyyy' |
                  'mm-dd-yyyy' | 'dd/mm/yyyy' | 'dd-mm-yyyy' | 'dd.mm.yyyy',
    decimal_separator = '.' | ',',
    ignore_errors = False | True,
    ignore_duplicates = False | True,
    contains_header_row = False | True,
)

Stock Factors Functions

You can create and store a custom stock factor on the website which consists of a list of dates, tickers and their associated values.

stock_factor_create_update()

Wrapper for POST​/stockFactor

Create or update a new stock factor. When the id is omitted a new factor will be created and the new id is returned.

p123api.Client().stock_factor_create_update({
    'name': 'FactorName',
    # Omit the id to create a new factor 
    'id' : id
    # Optional parameters
    'description': 'Description'
})

stock_factor_delete()

Wrapper for DELETE​/stockFactor​/{id}

Delete a stock factor.

p123api.Client().stock_factor_delete(
     factor_id = id
)

stock_factor_upload()

Wrapper for POST​/stockFactor​/upload​/{id}

Upload data from a csv file into an existing stock factor

p123api.Client().stock_factor_upload(
    file = 'C:/MyPath/Factors.csv',
    factor_id = id,
    column_separator = 'comma' | 'semicolon' | 'tab',
    existing_data = 'overwrite' | 'skip' | 'delete',
    date_format = 'yyyy-mm-dd' | 'yyyy/mm/dd' | 'mm/dd/yyyy' |
                  'mm-dd-yyyy' | 'dd/mm/yyyy' | 'dd-mm-yyyy' | 'dd.mm.yyyy',
    decimal_separator = '.' | ',',
    ignore_errors = False | True,
    ignore_duplicates = True | False
)