Alpha Factors and Alpha Trading in Python

Alpha Factors and Alpha Trading in Python

Table of contents

Alpha Factor in Python: Modeling for Advanced Trading Strategies

Alpha Trading is the way to model Alpha Factors in return exposure scenarios. These models are gaining popularity among investors of all levels thanks to greater technological accessibility.

Alpha factor decomposition
Factor decomposition: Market, Size, Value, Alpha

What is an Alpha Factor?

It is a relatively new concept where traditional explanations do not reflect the dynamic reality of this investment modality. The world of cryptoassets has attracted brilliant researchers who have generated new backtesting models with criteria different from the classic ones. These return-generation processes operate in a paradigm that traditional investors or technical analysts would find difficult to understand.

![Alpha Factor Overview](https://pythonparatrading.com/content/imagesilo of investment that assumes:

  • Markets are stochastic processes that do not follow a normal distribution, and past returns do not guarantee future returns. Therefore, asset universe selection methods are random in many phases of the research process, using only 20% real data and 80% time series generated through stochastic replication techniques.
  • Advanced overfit and position sizing processes are implemented to ensure model robustness. Evaluation is performed using ratios that standardize return levels and ranges of invariability against stochastic events.
  • The complete mathematization of the signal generation process enables current-state studies (nowcasting) and evaluation of the continuity of model robustness.

The Alpha Factor maintains a strong association with the scientific method, performing inference models with acceptable scientific rigor.

![Research methods](https://pythonparatrading.comdecuadamente, first we must understand what alpha is. The return of an alpha model can be represented as:

$$R_t = R_t * \alpha - R_t * \beta + e$$

Splitting the return into beta factor (market return) and alpha factor (return in addition to the market). We define alpha as the return coming from exposure that does not correspond in time with the behavior of the underlying asset.

A 100% beta strategy would be buy and hold, while a 100% Alpha strategy would be opportunistic, operating only under certain specific conditions.

An Alpha Factor is a set of rules and procedures that, starting from a mathematical formulation, generates return exposures using alternative methodologies for extracting advantages.

Alpha Encodings

Alpha encoders standardize and mathematize signals within the philosophy of trading systems. For example, we could generate signals from a basic trend following system with a moving average crossover:

$$sign(minus(ma_{30}(close),ma_{200}(close)))$$

This generates a binary response based on the subtraction between two moving averages (30, 200). However, the entropy of these signals is too high, similar to using random entries and exits. To improve, we can use more analogous formulas:

$$plus( \ sign(minus(ma_{20}(close),ma_{50}(close))), \ sign(minus(ma_{50}(close),ma_{100}(close))), \ sign(minus(ma_{100}(close),ma_{200}(close))) \ )$$

This provides robustness through the validation of previous signals, creating a "committee" that demands higher thresholds to make state changes.

The possibilities for encoding alpha are endless. Large banks typically use these encodings in momentum strategies and long/short arbitrage. We could even test the effect of post-earnings announcements in a simple way:

$$div(epsDifference,std_{12}(epsDifference))$$

Asset Universes

![Universes](https://pythonparatrading.comsos are subgroups of candidate assets for alpha exposure. The conditions for their generation have no limits: from 100% random universes to market capitalization criteria, sectors, fundamentals, macroeconomic or statistical characteristics.

Dynamic universes periodically re-evaluate the included assets. For example, the S&P 500 selects companies under specific criteria:

S&P 500. The index measures the performance of large market capitalization (Large Cap). Considered the most descriptive indicator of the U.S. capital markets. The index is composed of 500 companies.

To calculate the weight of each asset, the following formula is used:

$$p_a = MktCap / GlobalMktCap$$

This allows exactly replicating the same index weighting without ambiguities.

Universe Selection in Python

Let us create universes of candidate assets. We will start with a 100% random selection to avoid bias:

import pandas as pd
def random_tickers(x):
    tables=pd.read_html("https://en.wikipedia.org/wiki/List_of_S%26P_500_companies")
    tickers = tables[0]['Symbol'].tolist()
    return random.choices(tickers,k=x)

We can also refine the process using established ETFs as a reference:

import pandas as pd

urls = ['https://www.blackrock.com/es/profesionales/productos/253743/ishares-sp-500-b-ucits-etf-acc-fund/1497267045693.ajax?fileType=csv&fileName=CSPX_holdings&dataType=fund',
       'https://www.blackrock.com/es/profesionales/productos/253741/ishares-nasdaq-100-ucits-etf/1497267045693.ajax?fileType=csv&fileName=CSNDX_holdings&dataType=fund',
       'https://www.blackrock.com/es/profesionales/productos/251382/ishares-msci-world-minimum-volatility-ucits-etf/1497267045693.ajax?fileType=csv&fileName=MVOL_holdings&dataType=fund',
       'https://www.blackrock.com/es/profesionales/productos/280507/ishares-sp-500-health-care-sector-ucits-etf/1497267045693.ajax?fileType=csv&fileName=IUHC_holdings&dataType=fund']

allz = pd.DataFrame()
for x in range(len(urls)):
    tempz = pd.read_csv(urls[x],skiprows=2)
    allz = pd.concat([tempz,allz])
allz = allz[allz['Asset Class'] == 'Equity']
print('Cargados',len(allz['Ticker'].unique()),'tickers en un total de ',len(allz['Sector'].unique()),'Sectores')
allz = allz.set_index('Ticker')
allz['Market Value'] = allz['Market Value'].str.replace('.', '').str.replace(',', '.')
allz['Market Value'] = allz['Market Value'].astype(float)

To convert the candidates to list format:

tickers_candidatos = allz.index.tolist()

Or to access tickers from a specific sector:

allz[allz['Sector'] == 'Cuidado de la Salud'].index.tolist()

It is important to note that we are not selecting stocks where our system performs better (which would introduce overfit), but rather creating models that apply across all assets and select the most suitable ones.

Introduction to Alpha Factors in Python: Practical Implementation

We will explore different logics to research Alpha Factors. This article presents basic tools to transform a mathematical formula into a functional model.

Plan of Attack

  • Load the necessary libraries and tools
  • Program the helper functions
  • Program the main optimization engine
  • Integrate all the pieces into the pipeline

Tools Used

We will use standard Python libraries and yfinance to streamline data downloading.

import pandas as pd
import numpy as np
import scipy as sc
import matplotlib.pyplot as plt
import yfinance as yf
import itertools
from IPython.display import clear_output
plt.style.use("quantarmy")

Programming Helper Functions

We create functions for repetitive tasks:

def calc_skew(data,y):
    skew = data.rolling(y).skew()
    return skew

def calc_rets(data,y):
    rets = data.pct_change(y)
    return rets
    
def calc_delta(d1,d2):
    delta = d1 - d1.shift(d2)
    return delta

Programming the First Alpha with a Multi-Asset Approach

We will test the alpha on different assets to estimate its performance:

def backtest_alpha_01(data,ret_x=10,days_delta=10,rolling_skew=10,p=1.0):
    for d in ['SPY','QQQ','IWM','TLT','GLD']:
        data = yf.download(d,progress=False)[['Adj Close']].round(2)
        df = data[['Adj Close']].round(2)
        df['c_ret'] = df['Adj Close'].pct_change(ret_x)
        df['skew'] = df['c_ret'].rolling(rolling_skew).skew()
        df['abs'] = np.abs(df['skew'])
        df['alpha'] = calc_delta(df['abs'],days_delta)
        df['signal'] = np.where(df['alpha'] > p,1,0)
        df['pct'] = df['Adj Close'].pct_change()
        df['ret'] = df['pct'] * df['signal'].shift(1)
        df['ret'].cumsum().plot()
    plt.title('Basic Backtest over assets main assets')
    plt.legend(labels=['SPY','QQQ','IWM','TLT','GLD'])
    plt.show()
    return

![Alpha Factor on ETFs](https://pythonparatrading.com/content/ values (10, 10, 10, 1.0) are arbitrary. Results will vary depending on the parameters used to calculate the estimator and its cutoff points.*

$$IR = \frac{\mathbb{E}[\alpha]}{\sigma_\alpha} = \frac{\text{IC} \times \text{BR} \times \text{TC}}{\sigma_\alpha}$$

$$IC = \rho_{\alpha, \hat{\alpha}}$$

$$S = \frac{\mathbb{E}[R_p - R_f]}{\sigma_p}$$

Programming the Optimizer Engine

We create a function that traverses the entire spectrum of possible parameters:

def explore_alpha_01(df,ret_x=10,ret_y=16,days_delta_x=10,days_delta_y=16,rolling_skew_x=10,rolling_skew_y=16,p_x=1,p_y=2.1):
    eqs = pd.DataFrame()
    res = []
    i = 1
    
    retz = range(ret_x,ret_y,1)
    delt

Jesús Cuesta

Odesa (Ucrania)
Inversor desde 2014. Research desde 2017. He trabajado en diferentes gestoras de capital y Hedgefunds Crypto. Apasionado del codigo, los datos y las finanzas. Actualmente localizado en Ucrania.