Skip to main content

Overview

ClyptQ strategies are composed of Operator combinations. This framework supports everything from algorithmic strategies to AI-based strategies in a reproducible and verifiable manner.

Strategy Components

Strategies consist of 3 core elements: 1. Signal Generation
  • Alpha: Predictive signals
  • Factor: Systematic exposure
2. Universe Selection
  • Filter: Select tradable assets
  • Score: Ranking
3. Portfolio Construction
  • Optimizer: Weight optimization
  • Risk Management: Risk constraints

Signal Generation

Alpha Signals

Alpha represents signals that predict future returns:
# Momentum Alpha
class MomentumAlpha(Operator):
    role = OperatorRole.ALPHA

    def compute(self, data, timestamp, context):
        close = data["close"]

        # 20-day returns
        returns = (close.value[-1] / close.value[0]) - 1.0

        return TaggedArray(
            value=returns,
            exists=close.exists[-1],
            valid=close.valid[-1],
            updated=True
        )
Built-in Alphas:
  • MomentumAlpha: Trend following
  • MeanReversionAlpha: Mean reversion
  • RSIAlpha: RSI-based signals
  • VolumeAlpha: Volume-based
  • VolatilityAlpha: Volatility-based

Factor Signals

Factors represent systematic exposure:
# Market Beta Factor
class MarketBetaFactor(Operator):
    role = OperatorRole.FACTOR

    def compute(self, data, timestamp, context):
        returns = data["returns"]
        market_returns = data["market_returns"]

        # Calculate beta (covariance / variance)
        beta = np.cov(returns.value, market_returns.value)[0, 1] / \
               np.var(market_returns.value)

        return TaggedArray(value=beta, ...)
Common Factors:
  • Market Beta: Market exposure
  • Size: Market capitalization
  • Value: Value metrics
  • Momentum: Trend strength

Universe Selection

Filters

Filters select tradable assets (boolean output):
# Liquidity Filter
class LiquidityFilter(Operator):
    role = OperatorRole.FILTER

    def __init__(self, input_volume: Input, min_volume: float):
        self.min_volume = min_volume

    def compute(self, data, timestamp, context):
        volume = data["volume"]

        # Volume threshold
        meets_threshold = volume.value > self.min_volume

        return TaggedArray(
            value=meets_threshold.astype(float),  # 1.0 or 0.0
            exists=volume.exists,
            valid=volume.valid,
            updated=True
        )
Built-in Filters:
  • LiquidityFilter: Volume-based
  • PriceFilter: Price range
  • VolatilityFilter: Volatility criteria
  • CompositeFilter: Multiple filter combination (AND/OR)

Composite Filters

Combine multiple Filters:
# Filter combination
liquidity_filter = LiquidityFilter(
    Input("volume", lookback=20),
    min_volume=1_000_000
)

price_filter = PriceFilter(
    Input("close", lookback=1),
    min_price=1.0,
    max_price=1000.0
)

# AND combination
composite = CompositeFilter(
    inputs=[
        Input("liquidity_filter", lookback=1),
        Input("price_filter", lookback=1)
    ],
    logic="AND"  # "AND" or "OR"
)

Technical Indicators

ClyptQ provides 40+ technical indicators:

Trend Indicators

# Simple Moving Average
sma = SMA(Input("close", lookback=20), span=20)

# Exponential Moving Average (self-referencing)
ema = EMA(
    Input("close", lookback=1),
    Input("ema", lookback=1),  # Self-reference
    span=12
)

# MACD
macd = MACD(
    Input("close", lookback=26),
    fast=12,
    slow=26,
    signal=9
)

Momentum Indicators

# RSI
rsi = RSI(Input("close", lookback=14), period=14)

# Stochastic
stoch = Stochastic(
    Input("high", lookback=14),
    Input("low", lookback=14),
    Input("close", lookback=14),
    period=14
)

Volatility Indicators

# Bollinger Bands
bbands = BollingerBands(
    Input("close", lookback=20),
    period=20,
    std_dev=2.0
)

# ATR
atr = ATR(
    Input("high", lookback=14),
    Input("low", lookback=14),
    Input("close", lookback=14),
    period=14
)

Volume Indicators

# OBV (On-Balance Volume)
obv = OBV(
    Input("close", lookback=1),
    Input("volume", lookback=1)
)

# VWAP
vwap = VWAP(
    Input("close", lookback=1),
    Input("volume", lookback=1)
)

Performance Metrics

Metric Operators for measuring strategy performance:

Rolling Metrics

# Rolling Sharpe Ratio
rolling_sharpe = RollingSharpe(
    Input("returns", lookback=252),  # 1 year
    window=252,
    annualization=252
)

# Rolling Drawdown
rolling_dd = RollingDrawdown(
    Input("equity", lookback=252)
)

Accumulative Metrics

# Accumulative Sharpe (Welford's algorithm - O(1))
accum_sharpe = AccumSharpe(
    Input("returns", lookback=1),
    annualization=252
)

# Accumulative Returns
accum_returns = AccumReturns(
    Input("returns", lookback=1)
)
Rolling vs Accumulative:
  • Rolling: Fixed window, O(N×W) complexity
  • Accumulative: Entire period, O(1) complexity (Welford’s algorithm)

Strategy Patterns

Pattern 1: Trend Following

graph = ComputeGraph()

# Data
close = graph.add_node("close", FieldExtractor("close"))

# Indicators
sma_fast = graph.add_node("sma_fast",
    SMA(Input("close", lookback=10), span=10)
)
sma_slow = graph.add_node("sma_slow",
    SMA(Input("close", lookback=50), span=50)
)

# Signal: crossover
signal = graph.add_node("signal",
    CrossoverAlpha(
        Input("sma_fast", lookback=1),
        Input("sma_slow", lookback=1)
    )
)

# Filter: liquidity
universe = graph.add_node("universe",
    LiquidityFilter(
        Input("volume", lookback=20),
        min_volume=1_000_000
    )
)

# Apply filter to signal
filtered_signal = graph.add_node("filtered_signal",
    Multiply(
        Input("signal", lookback=1),
        Input("universe", lookback=1)
    )
)

Pattern 2: Mean Reversion

graph = ComputeGraph()

# Data
close = graph.add_node("close", FieldExtractor("close"))

# Bollinger Bands
bbands = graph.add_node("bbands",
    BollingerBands(Input("close", lookback=20), period=20, std_dev=2.0)
)

# Z-Score
zscore = graph.add_node("zscore",
    ZScore(Input("close", lookback=20))
)

# Signal: buy when oversold, sell when overbought
signal = graph.add_node("signal",
    MeanReversionAlpha(
        Input("zscore", lookback=1),
        threshold=2.0
    )
)

Pattern 3: Multi-Factor

graph = ComputeGraph()

# Factors
momentum = graph.add_node("momentum",
    MomentumAlpha(Input("close", lookback=20))
)

value = graph.add_node("value",
    ValueFactor(Input("fundamentals", lookback=1))
)

quality = graph.add_node("quality",
    QualityFactor(Input("fundamentals", lookback=1))
)

# Combine factors (equal weight)
combined = graph.add_node("combined",
    WeightedCombination(
        inputs=[
            Input("momentum", lookback=1),
            Input("value", lookback=1),
            Input("quality", lookback=1)
        ],
        weights=[0.33, 0.33, 0.34]
    )
)

# Rank and normalize
signal = graph.add_node("signal",
    ZScore(Input("combined", lookback=100))
)

Pattern 4: AI-Augmented

graph = ComputeGraph()

# Traditional signals
momentum = graph.add_node("momentum",
    MomentumAlpha(Input("close", lookback=20))
)

rsi = graph.add_node("rsi",
    RSI(Input("close", lookback=14), period=14)
)

# LLM-based sentiment
sentiment = graph.add_node("sentiment",
    LLMSentimentScorer(
        Input("news", lookback=1),
        model="gpt-4",
        prompt="Analyze sentiment: {news}"
    )
)

# Combine traditional + AI
signal = graph.add_node("signal",
    WeightedCombination(
        inputs=[
            Input("momentum", lookback=1),
            Input("rsi", lookback=1),
            Input("sentiment", lookback=1)
        ],
        weights=[0.4, 0.3, 0.3]
    )
)

Best Practices

1. Signal Normalization
# Raw signal → Normalize with Z-Score
raw_signal = MomentumAlpha(...)
normalized = ZScore(Input("raw_signal", lookback=100))
2. Universe Selection
# Always apply filters
signal = Alpha(...)
universe = LiquidityFilter(...)
filtered = Multiply(signal, universe)  # signal × filter
3. Performance Monitoring
# Add metrics
returns = Returns(Input("portfolio_value", lookback=1))
sharpe = AccumSharpe(Input("returns", lookback=1))
drawdown = RollingDrawdown(Input("portfolio_value", lookback=252))
4. Lookback Optimization
# Request only what's needed
Input("close", lookback=20)  # For SMA(20)

# Too much wastes memory
Input("close", lookback=1000)  # Avoid unless needed

Ecosystem Integration

For Builders:
  • Compose strategies with standard Operators
  • Same code for backtest → live
  • Ready for marketplace listing
For Buyers:
  • Transparent strategy components
  • Evaluate strategies with performance metrics
  • Understand risk profile