Skip to content
financial-time-series logo

Financial Time-Series Processing

financial-time-series

Use when working with price data, trading signals, or implementing momentum strategies. Covers returns calculation, volatility targeting, momentum factors, MACD indicators, time-series momentum (TSMOM), portfolio construction, futures contracts, and risk-adjusted returns for trend-following strat...

SKILL.md

Full skill instructions

Financial Time-Series Processing

Purpose

Comprehensive guide for processing financial time-series data and implementing trend-following strategies, based on the X-Trend model and Deep Momentum Networks framework.

When to Use

Activate this skill when:

  • Processing price data or returns
  • Calculating momentum factors or MACD indicators
  • Implementing volatility targeting
  • Building trend-following strategies
  • Constructing trading portfolios
  • Working with futures contracts
  • Calculating risk-adjusted returns (Sharpe ratio)

Core Concepts

1. Returns Calculation

Returns linearly de-trend the price series:

def calculate_returns(prices, lookback=1):
    """
    Calculate returns over specified lookback period.

    Args:
        prices: Array of daily close prices p[t]
        lookback: Number of days (t') for return calculation

    Returns:
        returns: r[t-t', t] = (p[t] - p[t-t']) / p[t-t']
    """
    return (prices - prices.shift(lookback)) / prices.shift(lookback)

Key Points:

  • Use daily close prices
  • Standard lookbacks: 1-day, 21-day (1-month), 63-day (3-month), 126-day (6-month), 252-day (1-year)
  • Returns remove price trends for stationarity

2. Volatility Targeting

Normalize positions by ex-ante volatility to ensure equal risk contribution:

def volatility_targeting(position, realized_vol, target_vol=0.15):
    """
    Scale position by volatility targeting leverage factor.

    Args:
        position: Raw trading signal z[t] in [-1, 1]
        realized_vol: Ex-ante volatility σ[t] (60-day EWMA)
        target_vol: Annual target volatility σ_tgt (typically 15%)

    Returns:
        scaled_position: Volatility-adjusted position
    """
    leverage = target_vol / realized_vol
    return position * leverage

Implementation:

  • Calculate σ[t] using exponentially weighted moving standard deviation over 60 days
  • Typical annual target: σ_tgt = 0.15 (15%)
  • Ensures each asset contributes approximately equal risk

3. Momentum Factors

Time-Series Momentum (TSMOM)

Classic momentum signal based on historical returns:

def tsmom_signal(returns_252):
    """
    Simple 1-year momentum signal.

    Args:
        returns_252: 252-day (1-year) returns

    Returns:
        signal: +1 (long) or -1 (short)
    """
    return np.sign(returns_252)
Multi-Scale Momentum

Combine signals at different timescales:

def multi_scale_momentum(prices):
    """
    Weighted combination of momentum at multiple timescales.

    Timescales:
        - 21 days (1-month)
        - 63 days (3-month)
        - 126 days (6-month)
        - 252 days (12-month)
    """
    timescales = [21, 63, 126, 252]
    weights = [0.25, 0.25, 0.25, 0.25]  # Equal weighting

    signals = []
    for t in timescales:
        ret = calculate_returns(prices, lookback=t)
        signals.append(np.sign(ret))

    return np.average(signals, weights=weights)
MACD (Moving Average Convergence Divergence)

Compare exponentially weighted signals at two timescales:

def macd_factor(prices, short=8, long=24, lookback_std=252):
    """
    Calculate MACD momentum indicator.

    MACD = (EWMA_short - EWMA_long) / std(prices_60)
    Normalized by std of past year returns

    Common timescale pairs: (8,24), (16,28), (32,96)

    Returns:
        macd: Normalized MACD signal
              > 0 indicates buy, < 0 indicates sell
              Magnitude indicates conviction
    """
    ewma_short = prices.ewm(span=short).mean()
    ewma_long = prices.ewm(span=long).mean()
    price_std = prices.ewm(span=60).std()

    m = (ewma_short - ewma_long) / price_std
    m_std = m.rolling(lookback_std).std()

    return m / m_std

MACD to Position Conversion:

def macd_to_position(macd_signal):
    """Convert MACD signal to position using response function."""
    return macd_signal * np.exp(-macd_signal**2 / 4) / 0.89

4. Deep Learning Momentum Factors

Normalized returns at multiple timescales for neural network inputs:

def normalized_returns(prices, volatility, timescales=[1, 21, 63, 126, 252]):
    """
    Calculate volatility-normalized returns for deep learning models.

    r_hat[t-t', t] = r[t-t', t] / (σ[t] * sqrt(t'))

    This normalization ensures returns are comparable across timescales.
    """
    factors = []
    for t in timescales:
        ret = calculate_returns(prices, lookback=t)
        r_normalized = ret / (volatility * np.sqrt(t))
        factors.append(r_normalized)

    return np.column_stack(factors)

Full Feature Vector:

def create_feature_vector(prices):
    """
    Create input features x[t] for deep momentum models.

    Includes:
    - Normalized returns at multiple timescales
    - MACD indicators at multiple (S, L) pairs
    """
    volatility = prices.pct_change().ewm(span=60).std()

    # Normalized returns
    norm_returns = normalized_returns(prices, volatility)

    # MACD features
    macd_features = [
        macd_factor(prices, 8, 24),
        macd_factor(prices, 16, 28),
        macd_factor(prices, 32, 96)
    ]

    return np.concatenate([norm_returns, macd_features])

5. Portfolio Construction

Calculate portfolio returns with volatility targeting and transaction costs:

def portfolio_returns(positions, returns, volatility, target_vol=0.15,
                     transaction_costs=0.0):
    """
    Calculate portfolio returns with volatility targeting.

    R_portfolio[t+1] = (1/​N) * Σ R[i, t+1]

    where for each asset i:
    R[i,t+1] = z[i,t] * (σ_tgt/σ[i,t]) * r[i,t+1]
               - C[i] * σ_tgt * |z[i,t]/σ[i,t] - z[i,t-1]/σ[i,t-1]|

    Args:
        positions: z[i,t] for each asset (N × T)
        returns: r[i,t+1] for each asset
        volatility: σ[i,t] for each asset
        target_vol: Annual target volatility σ_tgt
        transaction_costs: C[i] per asset

    Returns:
        portfolio_returns: R_portfolio[t+1]

    IMPORTANT: Transaction cost calculation uses position_changes which is
    already scaled by (target_vol / volatility), so we DON'T multiply by
    target_vol again. The formula is C * |scaled_pos[t] - scaled_pos[t-1]|,
    where scaled_pos = z * (σ_tgt/σ). This gives C * σ_tgt * |z/σ - z_prev/σ_prev|
    as per the paper's Eq. (2).
    """
    N = len(positions)

    # Scale by volatility targeting: scaled_pos = z * (σ_tgt/σ)
    scaled_positions = positions * (target_vol / volatility)

    # Asset returns
    asset_returns = scaled_positions * returns

    # Transaction costs
    # position_changes is already in units of σ_tgt * |z/σ - z_prev/σ_prev|
    # So we only multiply by transaction_costs C, NOT by target_vol again
    position_changes = np.abs(
        scaled_positions - scaled_positions.shift(1)
    )
    costs = transaction_costs * position_changes

    # Net returns per asset
    net_returns = asset_returns - costs

    # Equal-weighted portfolio
    return net_returns.mean(axis=0)

6. Risk-Adjusted Returns

Sharpe Ratio

Primary metric for strategy evaluation:

def sharpe_ratio(returns, periods_per_year=252):
    """
    Calculate annualized Sharpe ratio.

    Sharpe = sqrt(252) * mean(returns) / std(returns)

    Measures returns per unit volatility.
    """
    return np.sqrt(periods_per_year) * returns.mean() / returns.std()
Sharpe Loss for Neural Networks

Differentiable loss function for direct Sharpe optimization:

def sharpe_loss(positions, returns, volatility, target_vol=0.15):
    """
    Negative Sharpe ratio loss for gradient descent.

    L_Sharpe = -sqrt(252) * mean_batch(R[t+1]) / std_batch(R[t+1])

    where R[t+1] = (σ_tgt/σ[t]) * r[t+1] * position[t]

    This is the loss function used in Deep Momentum Networks.
    """
    scaled_returns = (target_vol / volatility) * returns * positions

    mean_ret = scaled_returns.mean()
    std_ret = scaled_returns.std()

    return -np.sqrt(252) * mean_ret / std_ret

7. Futures Contracts Handling

Continuous Futures
def create_continuous_contract(contracts, method='ratio_adjusted'):
    """
    Chain futures contracts into continuous series.

    Methods:
    - 'ratio_adjusted' (backwards): Multiply historical prices by ratio
    - 'difference_adjusted': Add price differences

    Ratio-adjusted method:
    - Preserves percentage returns
    - Preferred for momentum strategies
    - Used in Pinnacle Data CLC Database
    """
    if method == 'ratio_adjusted':
        # When rolling from contract C1 to C2:
        # Adjustment_ratio = P_C1(roll_date) / P_C2(roll_date)
        # Apply ratio to all historical prices before roll_date
        pass  # Implementation details

    return continuous_prices

8. Performance Metrics

def calculate_metrics(returns):
    """
    Calculate comprehensive performance metrics.

    Returns:
        metrics: Dict with Sharpe, returns, volatility, drawdown
    """
    cumulative_returns = (1 + returns).cumprod()
    running_max = cumulative_returns.expanding().max()
    drawdown = (cumulative_returns - running_max) / running_max

    return {
        'sharpe': sharpe_ratio(returns),
        'annual_return': returns.mean() * 252,
        'annual_volatility': returns.std() * np.sqrt(252),
        'max_drawdown': drawdown.min(),
        'cumulative_return': cumulative_returns.iloc[-1] - 1
    }

Common Patterns

Pattern 1: Basic TSMOM Strategy

def tsmom_strategy(prices, target_vol=0.15):
    """Implement basic time-series momentum strategy."""
    # 1. Calculate 1-year returns
    returns_252 = calculate_returns(prices, lookback=252)

    # 2. Generate signal
    signal = np.sign(returns_252)

    # 3. Calculate realized volatility (60-day EWMA)
    realized_vol = prices.pct_change().ewm(span=60).std()

    # 4. Apply volatility targeting
    position = volatility_targeting(signal, realized_vol, target_vol)

    # 5. Calculate returns
    next_day_returns = prices.pct_change().shift(-1)
    strategy_returns = position * next_day_returns * (target_vol / realized_vol)

    return strategy_returns

Pattern 2: Multi-Asset Portfolio

def multi_asset_portfolio(asset_prices_dict, target_vol=0.15):
    """
    Construct equal-risk portfolio across multiple assets.

    Args:
        asset_prices_dict: {'ASSET1': prices1, 'ASSET2': prices2, ...}
    """
    asset_returns = {}

    for asset, prices in asset_prices_dict.items():
        # Generate signal for each asset
        signal = tsmom_signal(calculate_returns(prices, 252))
        volatility = prices.pct_change().ewm(span=60).std()
        position = volatility_targeting(signal, volatility, target_vol)

        # Calculate asset returns
        next_ret = prices.pct_change().shift(-1)
        asset_returns[asset] = position * next_ret * (target_vol / volatility)

    # Equal-weighted portfolio
    portfolio = pd.DataFrame(asset_returns).mean(axis=1)

    return portfolio

Best Practices

DO:

✅ Always use volatility targeting for risk normalization ✅ Calculate ex-ante volatility using 60-day EWMA of returns ✅ Use backward ratio-adjusted continuous futures for consistent returns ✅ Test on out-of-sample data with expanding window approach ✅ Monitor drawdowns especially during regime changes ✅ Use multiple timescales to balance trend capture vs. responsiveness

DON'T:

❌ Don't assume Gaussian returns - especially in tails ❌ Don't ignore transaction costs - they compound over time ❌ Don't overfit to training period - financial markets are non-stationary ❌ Don't use look-ahead data - ensure causality in backtests ❌ Don't neglect correlation in tail events across assets

Key Formulas Reference

ConceptFormulaNotes
Returnsr[t-t',t] = (p[t] - p[t-t']) / p[t-t']Simple returns over t' days
Normalized Returnsr_hat[t-t',t] = r[t-t',t] / (σ[t] * sqrt(t'))For neural network inputs
Volatility Targetingleverage = σ_tgt / σ[t]Ex-ante vol σ[t] from 60-day EWMA
TSMOM Signalz[t] = sign(r[t-252,t])+1 for uptrend, -1 for downtrend
MACD(EWMA_S - EWMA_L) / std(m[-252:])Compare short/​long EWMAs
Portfolio ReturnR_port = (1/​N) * Σ R[i,t+1]Equal-weighted across N assets
Sharpe Ratiosqrt(252) * mean(R) / std(R)Annualized risk-adjusted returns

Related Concepts

  • Regime Change: Sudden market condition shifts (e.g., COVID-19)
  • Momentum Crashes: Rapid reversals causing losses
  • Factor Crowding: Too many strategies trading same signals
  • Mean Reversion: Price tendency to return to long-term mean
  • Commodity Trading Advisors (CTAs): Funds using trend-following

References

  • Time Series Momentum (Moskowitz, Ooi, Pedersen 2012)
  • Deep Momentum Networks (Lim, Zohren, Roberts 2019)
  • X-Trend: Few-Shot Learning Patterns (Wood, Kessler, Roberts, Zohren 2024)

Last Updated: Based on X-Trend paper (March 2024) Skill Type: Domain Knowledge Line Count: ~490 (under 500-line rule ✅)

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View