Synthetic Pair & Basket Constructor
import pandas as pd
import numpy as np
class SyntheticPairBuilder:
@staticmethod
def build_basket(prices: pd.DataFrame, weights: dict, name: str = "BASKET") -> pd.Series:
"""Construct a synthetic instrument from weighted price series."""
normalized = prices / prices.iloc[0] # Normalize to 1.0
basket = sum(normalized[sym] * w for sym, w in weights.items() if sym in normalized.columns)
basket.name = name
return basket
@staticmethod
def dxy_replica(prices: pd.DataFrame) -> pd.Series:
"""Replicate the US Dollar Index from FX pairs."""
weights = {"EURUSD": -0.576, "USDJPY": 0.136, "GBPUSD": -0.119,
"USDCAD": 0.091, "USDSEK": 0.042, "USDCHF": 0.036}
# Invert pairs where USD is quote currency
adjusted = prices.copy()
for pair in ["EURUSD", "GBPUSD"]:
if pair in adjusted.columns:
adjusted[pair] = 1 / adjusted[pair]
return SyntheticPairBuilder.build_basket(adjusted, {k: abs(v) for k, v in weights.items()}, "DXY_SYNTHETIC")
@staticmethod
def risk_on_off_basket(prices: pd.DataFrame) -> dict:
"""Build risk-on and risk-off baskets for sentiment measurement."""
risk_on = {"AUDUSD": 0.33, "NZDUSD": 0.33, "USDCAD": -0.34} # long AUD/NZD, short USD/CAD
risk_off = {"USDJPY": -0.5, "USDCHF": -0.5} # long JPY, CHF
return {
"risk_on_basket": SyntheticPairBuilder.build_basket(prices, risk_on, "RISK_ON"),
"risk_off_basket": SyntheticPairBuilder.build_basket(prices, risk_off, "RISK_OFF"),
}
@staticmethod
def optimal_basket_weights(prices: pd.DataFrame, target: pd.Series,
method: str = "ols") -> dict:
"""Find optimal weights to replicate a target series."""
from sklearn.linear_model import LinearRegression
normalized_prices = prices / prices.iloc[0]
normalized_target = target / target.iloc[0]
aligned = pd.concat([normalized_prices, normalized_target.rename("target")], axis=1).dropna()
X = aligned.drop("target", axis=1)
y = aligned["target"]
model = LinearRegression(fit_intercept=False).fit(X, y)
weights = dict(zip(X.columns, np.round(model.coef_, 4)))
r_squared = round(model.score(X, y), 4)
return {"weights": weights, "r_squared": r_squared,
"tracking_error": round((y - model.predict(X)).std(), 6)}
1---2name: synthetic-pair-constructor3description: Build custom synthetic instruments from weighted pair combinations. Use this skill whenever the user asks about "synthetic pair", "basket construction", "custom index", "weighted basket", "create a currency basket", "DXY replica", "synthetic instrument", "pair basket", "composite instrument", "trade a basket", or any request to construct custom tradeable instruments from multiple pairs. Works with pair-correlation-engine and portfolio-optimizer.4---56# Synthetic Pair & Basket Constructor78```python9import pandas as pd10import numpy as np1112class SyntheticPairBuilder:1314 @staticmethod15 def build_basket(prices: pd.DataFrame, weights: dict, name: str = "BASKET") -> pd.Series:16 """Construct a synthetic instrument from weighted price series."""17 normalized = prices / prices.iloc[0] # Normalize to 1.018 basket = sum(normalized[sym] * w for sym, w in weights.items() if sym in normalized.columns)19 basket.name = name20 return basket2122 @staticmethod23 def dxy_replica(prices: pd.DataFrame) -> pd.Series:24 """Replicate the US Dollar Index from FX pairs."""25 weights = {"EURUSD": -0.576, "USDJPY": 0.136, "GBPUSD": -0.119,26 "USDCAD": 0.091, "USDSEK": 0.042, "USDCHF": 0.036}27 # Invert pairs where USD is quote currency28 adjusted = prices.copy()29 for pair in ["EURUSD", "GBPUSD"]:30 if pair in adjusted.columns:31 adjusted[pair] = 1 / adjusted[pair]32 return SyntheticPairBuilder.build_basket(adjusted, {k: abs(v) for k, v in weights.items()}, "DXY_SYNTHETIC")3334 @staticmethod35 def risk_on_off_basket(prices: pd.DataFrame) -> dict:36 """Build risk-on and risk-off baskets for sentiment measurement."""37 risk_on = {"AUDUSD": 0.33, "NZDUSD": 0.33, "USDCAD": -0.34} # long AUD/NZD, short USD/CAD38 risk_off = {"USDJPY": -0.5, "USDCHF": -0.5} # long JPY, CHF39 return {40 "risk_on_basket": SyntheticPairBuilder.build_basket(prices, risk_on, "RISK_ON"),41 "risk_off_basket": SyntheticPairBuilder.build_basket(prices, risk_off, "RISK_OFF"),42 }4344 @staticmethod45 def optimal_basket_weights(prices: pd.DataFrame, target: pd.Series,46 method: str = "ols") -> dict:47 """Find optimal weights to replicate a target series."""48 from sklearn.linear_model import LinearRegression49 normalized_prices = prices / prices.iloc[0]50 normalized_target = target / target.iloc[0]51 aligned = pd.concat([normalized_prices, normalized_target.rename("target")], axis=1).dropna()52 X = aligned.drop("target", axis=1)53 y = aligned["target"]54 model = LinearRegression(fit_intercept=False).fit(X, y)55 weights = dict(zip(X.columns, np.round(model.coef_, 4)))56 r_squared = round(model.score(X, y), 4)57 return {"weights": weights, "r_squared": r_squared,58 "tracking_error": round((y - model.predict(X)).std(), 6)}59```