Features
Hermes turns raw datasets into derived intelligence through a tiered, dependency-aware feature engine that records lineage. ~57 features ship across five country-risk groups plus technical, fundamental, crypto-history and filing feature sets.
Feature groups at a glance
| Group | Count | Source(s) | Status |
|---|---|---|---|
| Economic | 18 | World Bank + IMF | Working |
| Environmental | 6 | ND-GAIN + World Bank | Partial (2 placeholders) |
| Security | 7 | SIPRI / NATO datasets | Partial (4 placeholders) |
| Social | 6 | World Bank + HRS / FSI / HDI | Partial (1 placeholder) |
| Geopolitical | 21 | GDELT / WGI | Stubbed |
| Technical (crypto) | ~50 per snapshot | Binance | Working |
| Fundamental | CompanyFundamental | SEC + Finnhub + FRED + yfinance | Working |
| Filing (crypto fam) | — | SEC facts | Working |
Country-risk features are the bread-and-butter: five groups covering the dimensions that matter when assessing a sovereign. Financial features layer market and company intelligence on top.
The feature engine
The core abstraction lives in hermes/features/. The features registry (constructed with features(os_api)) exposes five country-risk groups and list_features() returns every registered callable.
class features:
def __init__(self, os_api: str):
self.eco = economic_features()
self.env = enviromental_features()
self.geo = geopolitical_features(os_api=os_api)
self.sec = security_features()
self.soc = social_features()
def list_features(self) -> list[Callable]@feature, LineageGraph & TieredPlan
Features register themselves through a @feature decorator that records their name, group, dependencies and compute expression into a module-level singleton lineagegraph = LineageGraph():
from hermes.features import feature
@feature(
name="gdp_growth_5y",
group="economic",
deps=["economic:gdp_growth_yoy"],
compute="rolling(5).mean()",
)
async def compute_growth(df, config):
return df["gdp_growth"].rolling(5).mean()LineageGraph.register_feature(name, group, deps, compute, fn) stores the record and appends the name to groups[group]. resolve_group(group) performs a topological layering: it repeatedly emits a tier of features whose cross-feature dependencies are already satisfied, producing a TieredPlan(tiers, all_features). The graph and tiers persist to JSON via save(path) / load(path) (functions are dropped on load).
Country-risk features
Every country-risk feature shares the signature async <feature>(country_code, mode="F"). mode="F" returns the latest scalar; mode="ML" returns a pd.Series indexed by year (2000–2025, forward-filled). Helper adjust_year_range(df, year_col, start, end, fill_method, fill_value) merges onto the full year range with value/ffill/bfill/linear fills.
Economic (18)
World Bank + IMFgdp_growth_yoy NY.GDP.MKTP.KD.ZG GDP growth YoY (%)
gdp_growth_qoq NY.GDP.MKTP.KD GDP growth QoQ
industrial_production_yoy NV.IND.MANF.KD.ZG industrial production YoY
inflation_cpi_yoy FP.CPI.TOTL.ZG CPI inflation YoY
inflation_volatility_12m FP.CPI.TOTL CPI YoY rolled 12-period std
ppi_yoy IMF ...PPI.IX.A producer price index YoY
inflation_yoy IMF ...CPI._T.IX.M inflation YoY (monthly)
unemployment_rate SL.UEM.TOTL.ZS
youth_unemployment SL.UEM.1524.ZS
labor_force_participation SL.TLF.CACT.ZS
current_account_gdp_ratio BN.CAB.XOKA.GD.ZS
fx_reserves_months_import FI.RES.TOTL.MO
external_debt_gdp_ratio DT.DOD.DECT.GN.ZS
fiscal_deficit_gdp IMF WEO GGXCNL_NGDP
government_debt_gdp IMF WEO GGXWDG_NGDP
reer_misalignment IMF ...EREER_IX.M
banking_sector_health FB.AST.NPLN.ZS
gdp_per_capita_ppp NY.GDP.PCAP.PP.CDEnvironmental (6)
ND-GAIN + World Bank- climate_vulnerability_score — NDGAIN CVS dataset score (implemented)
- climate_readiness_score — NDGAIN CRS dataset score (implemented)
- energy_dependence_ratio — WB EG.IMP.CONS.ZS (implemented)
- water_stress_index — WB ER.H2O.FWTL.ZS (implemented)
- natural_disaster_risk — placeholder
- food_price_index_change_yoy — placeholder
Security (7)
SIPRI / NATO datasets- military_spending_gdp — SIPRI military expenditure % of GDP (implemented)
- military_spending_growth_yoy — SIPRI pct_change(1)*100 (implemented)
- nato_member — NATO membership bool, deps=['nato:membership'] (implemented)
- alliance_strength_score, arms_imports_12m, arms_exports_12m, peacekeeping_troops — placeholders
Social (6)
World Bank + HRS / FSI / HDI datasets- human_rights_score — HRS dataset human_right_score
- fragile_state_index — FSI dataset Total (0–120)
- human_development_index — HDI dataset score
- gini_coefficient — WB SI.POV.GINI
- poverty_headcount_ratio — WB SI.POV.DDAY
- social_stability_index — placeholder
Geopolitical (21)
stubbed — NotImplementedError pending GDELT/WGI rebuildThe public API surface is preserved: conflict_event_count_30d/90d, conflict_trend, goldstein_scale_avg_30d, goldstein_scale_trend, battle_deaths_30d/90d, protest_event_count_30d, protest_violence_level, diplomatic_event_count_30d, diplomatic_intensity_avg, sanctions_count_active, sanctions_new_30d, sanctions_sector_coverage, governance_wgi_composite, corruption_perception_index, rule_of_law_score, regulatory_quality, democracy_index, regime_type (democracy | hybrid | autocracy), press_freedom_score.
The country-risk pipeline
The pipeline class coordinates the groups. get_country_risk_features(country) validates the ISO3 code, runs all features concurrently with asyncio.gather (a _safe_call swallows exceptions into None), and returns:
{
"country": "USA",
"economic": {...}, # feature -> value
"geopolitical": {...},
"security": {...},
"social": {...},
"environmental": {...},
"metadata": {
"last_updated": ...,
"features_version": "1.0.0",
},
}build_training_panel(fns, countries) calls each function with mode="ML" across countries and stacks them into a pd.DataFrame with a MultiIndex of (country_iso3, date) — ready for supervised modeling.
Financial features
Technical analysis — TAfeatures (crypto, via Binance)
Helpers: _sma, _ema (pandas ewm, adjust=False), _zscore (sample std, ddof=1), _returns (log returns). Methods each return a dict of features:
| Method | Features computed |
|---|---|
| calculate_price_features(candles) | open, high, low, close, volume, quote_volume, ret_1b/5b/10b/60b, ret_open_to_close, hl_range, body_range, dist_sma_20/50/200, ema_diff_9_21, ema_diff_21_50, vol_20, vol_60, atr_14_norm, volume_rel_20, taker_buy_vol_ratio |
| trade_features(symbol, limit=1000) | trades_count, trade_window_*, trade_buy_vol_ratio, avg_trade_size, median_trade_size, large_trade_vol_ratio (95th pct) |
| orderbook_features(symbol, limit=20) | bid/ask price & qty, spread_abs, spread_bps, top_book_imbalance, depth_bid_total, depth_ask_total, depth_imbalance |
| day_features(symbol) | high/low/last_24h, range_24h, pct_change_24h, pos_in_24h_range, volume_24h, quote_volume_24h |
| funding_features(symbol, limit=30) | funding_rate, funding_rate_lag_3, funding_rate_change, funding_rate_zscore |
| oi_features(symbol) | open_interest, oi_change_1h, oi_change_24h |
| positioning_features(symbol, period='1h', limit=30) | trend_score, mean_reversion_score, liquidity_score, order_flow_score, sentiment_score |
build_snapshot(symbol) (→ TechnicalSnapshot dataclass, ~50 fields) adds oi_to_volume_24h; get_technical(symbol) returns snapshots.
Crypto history — CryptoHistory
get_history(symbol, interval='1d', market='future', years=2) fetches Binance history and computes a vectorized rolling feature set ( TechnicalHistoryRow, ~90 fields) including: log returns ret_1b/3b/5b/10b/20b/60b, rsi_14 (Wilder), macd/macd_signal/macd_hist, Bollinger bb_upper/lower/width/pct, obv, returns_skew_20/returns_kurt_20, drawdown, amihud_illiquidity, plus extended volume/z-score/trend/ratio features.
Fundamental analysis — FAfeatures
Combines SEC facts + filing metadata + Finnhub metrics + FRED macro + yfinance estimates into a CompanyFundamental row via get_fundamentels(symbol). Notable helpers:
- extract_funds_sec(data) — maps SEC us-gaap facts through SEC_TAG_MAP to most-recent values
- extract_filing_meta(data) — filing_date, fiscal_year, fiscal_period, filing_type
- macro() — FRED GDP, CPI, FEDFUNDS, UNRATE, GFDEBTN, exchange rates
- Computes revenue_surprise = (revenue − revenue_estimate) / revenue_estimate
- Ratio metadata aliases: P/E, P/S, P/B, EV/EBITDA, ROE, ROA, Debt/Equity
Company filings — CompanyFiling
get_history(quarters=8, symbols=None) fetches SEC facts for each ticker and computes filing-derived fundamentals with true YoY matching by fiscal period. Feature families: growth, margins, liquidity, leverage, cash-flow quality, efficiency, balance-sheet growth, shareholder (share_count/buyback/dividend change), and coverage (interest_coverage). get_candle_history pulls candles via Finnhub with automatic yfinance fallback when fewer than 100 rows.
Compute through the facade
from hermes import Hermes
hermes = Hermes(opensanction_api="x", new_data_api="x",
sec_username="x", sec_email="x")
# Full country-risk scan
scan = await hermes.country_features.get_country_risk_features("USA")
# Single economic feature, ML-mode series
series = await hermes.lf.eco.gdp_growth_yoy("USA", mode="ML")
# Technical snapshot for a crypto symbol
snap = hermes.ta_feature.get_technical("BTCUSDT")hermes/features/, and the analysis deep-dives in the repo under docs/analysis/fundamentals.md and docs/analysis/technical.md.