Captura de pantalla 2024 01 03 a las 7.18.02

Carlos Barredo Lago es Trader, investigador y desarrollador cuantitativo e Ingeniero Industrial. Ha destacado en el ámbito del trading algorítmico, especialmente en estrategias de baja latencia y microestructura del mercado. Ganador de la competición Robotrader en 2018. En 2019 fundó Qinvia, una empresa de prop trading establecida en Dubai, especializada en soluciones de trading algorítmico
Carlos Barredo Lago / Qinvia

 

  • En el vasto mundo del trading cuantitativo y las métricas de inversión, el foco a menudo recae sobre los retornos como ratio más destacado. Las estrategias que presumen de enormes beneficios pueden acaparar la atención, pero ¿son consistentemente confiables? Hablemos del Ratio Consistency-Weighted Return (CWR).
  • Artículo publicado en Hispatrading 56.

El ratio Consistency-Weighted Return (CWR) es una métrica diseñada para combinar el beneficio bruto con la consistencia de la estrategia que puede ayudarnos a medir de forma fiable una estrategia de trading.

¿Qué es el Consistency-Weighted Return (CWR)?

En el ámbito del trading y la inversión, una curva de rentabilidad ascendente y constante en las ganancias a menudo se considera el «santo grial». Esta consistencia deseada es más que un sueño; es un reflejo de la estabilidad y confiabilidad en la estrategia elegida.

El CWR ofrece un enfoque analítico para medir cuán cerca está una estrategia de trading de este escenario ideal. Combina los retornos totales de una estrategia con su valor R², también conocido como el coeficiente de determinación.

¿Pero qué es exactamente este R² o coeficiente de determinación? En la disciplina de las estadísticas, cuando buscamos entender la linealidad de un conjunto de puntos de datos, utilizamos un método llamado regresión lineal. A través de este método, nos esforzamos por ajustar una línea (a menudo referida como la «línea de mejor ajuste») entre estos puntos. El valor R² proviene de este procedimiento. Cuantifica la proporción de varianza en la variable dependiente (en este contexto, los retornos de una estrategia de trading) que es predecible a partir de la(s) variable(s) independiente(s). Esencialmente, un valor R² de 1 denota una relación lineal perfecta, lo que implica que los datos se alinean impecablemente con la línea de mejor ajuste. Por el contrario, un valor cercano a 0 sugiere una falta de linealidad, indicando que los puntos de datos están ampliamente dispersos alrededor de la línea.

Por lo tanto, el CWR no es simplemente un reflejo de las ganancias absolutas de una estrategia. Plantea una pregunta más intrincada: «¿Al generar estas ganancias, la estrategia mantuvo una apariencia de uniformidad y previsibilidad?»

Fórmula: CWR = R² × Retornos Anualizados

Donde:

R² (Coeficiente de Determinación): Es una métrica de confiabilidad. Un indicador de cuán armoniosamente los retornos de la estrategia se adhirieron a una regresión lineal.

Retornos Anualizados: Esta es la suma de todas las ganancias y pérdidas del período, escalada para representar un retorno anual. Específicamente, la fórmula para anualizar retornos simples es:

Retornos Anualizados = Retornos Totales × (duración en períodos / períodos por año)

Donde:

  • Retornos Totales: Los Retornos Totales son la suma acumulativa de los retornos diarios.
  • períodos por año: períodos por año sería 365 para criptomonedas y 252 para la mayoría de otros activos.
  • duración en períodos: la duración en períodos es el número total de días en su serie temporal.

¿Por qué CWR? La Ventaja de la Consistencia

  1. Pronósticos Confiables: Las estrategias con mayor consistencia son más predecibles. Tienden a mostrar menos fluctuaciones extremas, lo que las hace más fáciles de manejar y menos estresantes para los traders.
  2. Menor Riesgo: Retornos consistentes pueden sugerir que la estrategia no depende de grandes victorias ocasionales (que pueden ser seguidas de grandes pérdidas). Esto reduce el riesgo de pérdidas severas.
  3. Viabilidad a Largo Plazo: Si bien las estrategias de ‘éxito efímero’ pueden ofrecer retornos dramáticos durante un corto período, a menudo se desvanecen. Las estrategias consistentes, por otro lado, pueden ofrecer un rendimiento sostenido.

Calculando el ratio CWR con Python

En el proceso de obtención del ratio Consistency-Weighted Return (CWR), un componente crítico es el valor R², que esencialmente mide la consistencia de los retornos.

Para calcular R², el primer paso es realizar una regresión lineal en nuestro conjunto de datos para determinar la línea de mejor ajuste. Una distinción importante en nuestro enfoque es que optamos por no usar un intercepto u ordenada en el origen. Esta elección se basa en el principio fundamental de que se supone inherentemente que una curva de rentabilidad comienza en cero.

En esta sección, exploraremos dos métodos distintos para realizar la regresión lineal y, posteriormente, obtener el valor R²:

  1. Mínimos Cuadrados Ordinarios (OLS): Un método ampliamente utilizado en estadística, especialmente cuando se trata de datos multivariable. Utilizaremos la librería statsmodels en Python para este método.
  2. Método de Cálculo Directo: Este método, diseñado para la regresión lineal univariable, calcula la pendiente de la regresión usando la covarianza entre las variables y la varianza de la variable independiente. Utilizaremos este método para determinar el valor R², diferenciando entre la variación total y la variación explicada por el modelo de regresión.

Profundicemos en ambos métodos. Aquí hay una guía paso a paso usando un dataframe hipotético llamado trades:

1. Prepara tu entorno:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm

2. Crea un dataframe de trades de muestra:

# Simulando una serie pnl aleatoria pero rentable
bias = 0.25  # Esta constante asegura una tendencia ascendente en promedio
data = {
    ‘time’: pd.date_range(start=’2023-06-01′, periods=100, freq=’D’),
    ‘pnl’: np.random.randn(100) + bias
}
trades = pd.DataFrame(data)

trades[‘pnl’] = trades[‘pnl’] / len(trades)

3. Calcula los retornos acumulados y extrae los arrays ‘X’ e ‘y’:

# Retornos acumulados.

trades[‘cumpnl’] = trades[‘pnl’].cumsum()

# Crea el array X basado en la longitud de trades.

X = np.array(range(len(trades)))

# Crea ‘y’ basado en la columna ‘cumpnl’ de trades.
y = trades[‘cumpnl’].values

4.1. Calcula R² usando OLS:

# Ajusta el modelo OLS sin ordenada al origen.
model = sm.OLS(y, X).fit()

# Extrae R^2 directamente del modelo.
r_squared_ols = model.rsquared

4.2. Calcula R² usando el método directo:

# Calcula el coeficiente beta sin ordenada al origen.
beta = np.sum(X * y) / np.sum(X**2)

# Predice y usando el beta calculado.
y_pred_direct = beta * X

# Calcula R^2 directamente para el modelo sin ordenada al origen.
ss_tot_direct = np.sum(y**2)
ss_res_direct = np.sum((y – y_pred_direct)**2)
r_squared_direct = 1 – (ss_res_direct / ss_tot_direct)

5. Calcula CWR:

# Parámetros para la anualización
periods_per_year = 365  # Usando 365 para activos como criptomonedas

# Calcula la duración en periodos (días en este caso, ya que ‘trades’ es un dataframe de datos diarios)
duration_in_periods = len(trades)

# Calcula los retornos anualizados
annualized_returns_ols = trades[‘cumpnl’].iloc[-1] * (periods_per_year / duration_in_periods)
annualized_returns_direct = trades[‘cumpnl’].iloc[-1] * (periods_per_year / duration_in_periods)

# Calcula los CWR usando los valores R^2 y los retornos anualizados
cwr_ols = annualized_returns_ols * r_squared_ols
cwr_direct = annualized_returns_direct * r_squared_direct

# Imprime los resultados para una rápida comparación
print(f»CWR using OLS method: {cwr_ols:.6f}»)
print(f»CWR using Direct Calculation method: {cwr_direct:.6f}»)

CWR using OLS method: 0.935333
CWR using Direct Calculation method: 0.935333

6. Grafica los retornos comparados con las regresiones lineales:

# Línea de regresión para el método OLS:
regression_line_ols = model.predict(X)

# Línea de regresión para el método de cálculo directo:
regression_line_direct = beta * X

# Gráfico
plt.figure(figsize=(12, 5))

# Grafica el retorno acumulado real
plt.plot(trades[‘time’], trades[‘cumpnl’], label=’Cumulative PnL’, color=’green’)

# Grafica la línea de regresión obtenida del método OLS
plt.plot(trades[‘time’], regression_line_ols, label=’Regression (OLS)’, color=’black’, linestyle=’–‘)

# Grafica la línea de regresión obtenida del método de cálculo directo
plt.plot(trades[‘time’], regression_line_direct, label=’Regression (Direct)’, color=’grey’, linestyle=’–‘)

# Estableciendo títulos y etiquetas
plt.title(‘Cumulative PnL compared with Regression Lines’)
plt.xlabel(‘Time’)
plt.ylabel(‘Cumulative PnL’)
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

pastedGraphic.png
Figura 1. Retornos acumulados comparados con las líneas de regresión.

Rendimientos Espectaculares vs. Crecimiento Estable

Ilustremos la importancia del CWR con un ejemplo práctico.

Imagina dos estrategias de trading a lo largo de 100 días:

  • Estrategia A: Caracterizada por rendimientos espectaculares, esta estrategia a menudo ofrece ganancias significativas seguidas de caídas pronunciadas, asemejándose a una montaña rusa financiera. Es importante señalar que, por diseño, la Estrategia A termina con un rendimiento que es un 10% más alto que el de la Estrategia B al final del período.
  • Estrategia B: Esta estrategia enfatiza un crecimiento más estable. Aunque los rendimientos son más consistentes, hay un toque de ruido realista, lo que la hace menos predecible pero mucho más estable que la Estrategia A.

# Estableciendo la semilla para reproducibilidad
np.random.seed(17)

# Estrategia A: Retornos más volátiles
volatile_returns = np.random.randn(100) * 0.1
# Estrategia B: Retornos estables pero con ligero ruido
steady_returns = np.full(100, 0.005) + np.random.randn(100) * 0.01

# Ajustando A para asegurar que termine con un retorno un 10% más alto al final del período
cum_returns_A = volatile_returns.cumsum()
target_final_return = steady_returns.cumsum()[-1] + 0.10  # 10% más retorno que la estrategia B
scale_factor = target_final_return / cum_returns_A[-1] volatile_returns *= scale_factor

# Creando DataFrames para ambas estrategias
time_range = pd.date_range(start=’2023-06-01′, periods=100, freq=’D’)
trades_A = pd.DataFrame({‘time’: time_range, ‘returns’: volatile_returns})
trades_B = pd.DataFrame({‘time’: time_range, ‘returns’: steady_returns})

# Calculando el retorno acumulado para ambas estrategias
trades_A[‘cumpnl’] = trades_A[‘returns’].cumsum()
trades_B[‘cumpnl’] = trades_B[‘returns’].cumsum()

# Gráfico
plt.figure(figsize=(12, 6))
plt.plot(trades_A[‘time’], trades_A[‘cumpnl’], label=’Strategy A’, color=’red’)
plt.plot(trades_B[‘time’], trades_B[‘cumpnl’], label=’Strategy B’, color=’green’)
plt.title(‘Comparison of Cumulative PnL: Flashy Returns vs. Steady Growth’)
plt.xlabel(‘Time’)
plt.ylabel(‘Cumulative PnL’)
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

pastedGraphic_1.png
Figura 2. Comparación de los retornos acumulados: Rendimientos Espectaculares vs. Crecimiento Estable.

A pesar de que la Estrategia A tiene un retorno acumulado más alto al final de los 100 días, sus trayectorias difieren significativamente. Cuando evaluamos estas estrategias con la métrica CWR, emerge una visión más reveladora.

# Parámetros para anualización
periods_per_year = 365  # Usando 365 para activos como criptomonedas

# Calcular la duración en periodos (días en este caso, ya que trades_A y trades_B son dataframes de datos diarios)
duration_in_periods = len(trades_A)  # Suponiendo que trades_A y trades_B tienen la misma duración

# Estrategia A: Cálculo de CWR
X = np.arange(len(trades_A))
y_A = trades_A[‘cumpnl’].values
model_A = sm.OLS(y_A, X)
results_A = model_A.fit()
r_squared_A = results_A.rsquared
annualized_returns_A = trades_A[‘cumpnl’].iloc[-1] * (periods_per_year / duration_in_periods)
cwr_A = annualized_returns_A * r_squared_A

# Estrategia B: Cálculo de CWR
y_B = trades_B[‘cumpnl’].values
model_B = sm.OLS(y_B, X)
results_B = model_B.fit()
r_squared_B = results_B.rsquared
annualized_returns_B = trades_B[‘cumpnl’].iloc[-1] * (periods_per_year / duration_in_periods)
cwr_B = annualized_returns_B * r_squared_B

# Imprimiendo el CWR para ambas estrategias
print(f»CWR for Strategy A: {cwr_A:.4f}»)
print(f»CWR for Strategy B: {cwr_B:.4f}»)

CWR for Strategy A: 1.6648
CWR for Strategy B: 1.8462

Al calcular el ratio CWR para ambas estrategias usando el método OLS, la Estrategia B mostró un valor más alto, enfatizando su fiabilidad a pesar de tener un rendimiento total más bajo que la Estrategia A.

Este ratio no solo tiene en cuenta el “destino” sino también el “trayecto” realizado. Una estrategia con un crecimiento más predecible y constante probablemente tendrá un CWR más alto, destacando su rendimiento consistente. Esta consistencia puede ser más atractiva para los traders e inversores, ya que reduce la imprevisibilidad y el potencial estrés de los cambios erráticos en el rendimiento.

Incorporando el ratio CWR en la evaluación de tus estrategias:

  1. Compara y Contrasta: Usa CWR junto con otras métricas como el Ratio de Sharpe, Ratio de Sortino o el Máximo Drawdown para obtener una visión más integral del rendimiento de una estrategia.
  2. Construcción de Cartera: Para carteras diversificadas, asegúrate de tener una combinación de estrategias. Prioriza aquellas con un CWR más alto para aportar más estabilidad a tu cartera.
  3. Gestión de Riesgos: Identifica las estrategias con CWRs más bajos ya que pueden introducir más volatilidad. Ajusta tu asignación de capital en consecuencia.

Conclusión

Aunque los rendimientos brutos siempre serán una piedra angular al evaluar el rendimiento, el ratio Consistency-Weighted Return (CWR) ofrece una perspectiva novedosa, enfatizando la importancia de un crecimiento constante y confiable. En los mares tumultuosos del mundo del trading, una estrategia consistente puede ser el ancla que asegura el éxito a largo plazo.

Recuerda, al explorar nuevas métricas como CWR, es vital entender sus limitaciones y usarlas en conjunto con otras herramientas y ratios. ¡Buen trading!