Skip to main content

The MarketDX financial impact graph, in Python — news→market impact (why, who, direction, ripple) across stocks, commodities, FX, crypto, and private companies.

Project description

marketdx

The financial impact graph, in Python.
News → who it touches and why — the causal channel, the story's lean, and the ripple — across stocks, commodities, FX, crypto, and private companies.
A research, screening & feature layer — direction is the news's content lean, not a price forecast.

▶ Live playground · Docs & pricing · Sample dataset


pip install marketdx          # add [pandas] for .to_df():  pip install "marketdx[pandas]"

An API key is required. Create a free one at https://marketdx.lab.ai (sign in → API keys), then pass it to the client (keep it out of source control — read it from an env var / secret in real apps):

from marketdx import MarketDX

mdx = MarketDX(api_key="avn_live_…")                     # your key from https://marketdx.lab.ai
for s in mdx.news(megatrend="ai-power", impact="indirect"):
    print(s.title, [(e.name, e.impact.net_direction) for e in s.entities])

That's the whole graph: every news event, every affected entity, labeled with direction, relevance, the causal aspect (the why), and whether it's the epicenter or a ripple — across five asset classes, including private companies ticker feeds can't see.

No key yet? Explore everything with zero signup in the playground, then grab a free key at https://marketdx.lab.ai. Every request is authenticated with your key (Authorization: Bearer <key>) and metered in credits.

Why the SDK (not just requests)

  • Typed graphsignal.entities[0].impact.aspects[0].direction with autocomplete, not raw dicts.
  • Auto-paginationfor s in mdx.news(...) walks every page for you. Nothing to manage.
  • Names, not idsmegatrend="ai-power" or "AI Power & Cooling" or 10040000 all work.
  • .to_df() — the whole result as a pandas DataFrame, one row per (event × entity × aspect).
  • Typed errorsAuthError, QuotaError, RateLimitError, BadRequestError, NotFoundError.

The graph, a few ways

# 1. Ripple: a themed event that also touches NON-thematic entities (our differentiator)
for s in mdx.news(megatrend="semiconductors", impact="indirect", max_items=50):
    ...

# 2. Beyond tickers: private companies in a trend (OpenAI, Anthropic, Ampere, ChangXin…)
for c in mdx.megatrends("semiconductors").off_coverage():
    print(c.name, c.type, "→", c.megatrend["node_name"])

# 2b. …or just the NEWS that moves private companies — one server-side filter on the feed
for s in mdx.news(entity_type="private", only_scored=True):   # also: crypto / commodity / forex / stock
    print(s.title, [e.name for e in s.entities if e.type == "private"])

# 3. Per-stock impact timeline + its news-derived rivals
tl    = mdx.stock("NVDA.US").news(aspect="competition")
peers = mdx.stock("NVDA.US").competitors()

# 4. News-driven screen — where the news leans positive on a theme (the model's read, for research)
positive_lean = mdx.stocks(megatrend="ai-power", direction="pos", country="US", order_by="news_count")

# 5. Semantic search — match news by MEANING, not keywords
hits = mdx.news_search("chip export controls to China")

# 6. Theme brief in ONE call — pulse timeseries + top stories + winners/losers + heatmap + assets
brief = mdx.theme("ai-power").summary(window="qtd")     # 7d/30d/90d/1y or mtd/qtd/ytd
print(brief["pulse"]["story_count"], brief["pulse"]["net_direction"])
print([w["ticker"] for w in brief["winners"]], "vs", [l["ticker"] for l in brief["losers"]])
print([a["name"] for a in brief["top_assets"]])          # commodity / forex / crypto the theme moves

Straight to pandas

.to_df() returns the same columns as the sample dataset (impact-signals.csv) — so anything you prototyped on the free CSV runs unchanged on the live graph:

df = mdx.news(megatrend="ai-power", impact="indirect").to_df()
# published_at · title · brief_text · entity_name · entity_ticker · entity_type · direction ·
# aspect · reason · relevance · impact · impact_score · node_name · entity_country · publisher · url

df.groupby(["entity_type", "direction"]).size()      # who the news lands on, +/− by asset class (the model's read)
df[df.aspect == "tariff"].entity_name.value_counts()  # who the tariff channel touches

Filtering — read this before you filter

Feed filters are EVENT-level, not row-level. news(direction=…, aspect=…, news_type=…, country=…) selects articles that contain at least one matching impact and returns the whole article with all its entities and aspects. So direction="pos" can return an article that also moves something neg, and aspect="supply" can return one whose other entities are hit via monetary. For exact per-row filtering, post-filter the entities:

for s in mdx.news(news_type="commodity_supply", direction="pos"):
    for e in s.entities:
        for a in (e.impact.aspects if e.impact else []):
            if e.type == "commodity" and a.direction == "pos" and a.aspect == "supply":
                ...   # exact row you asked for

Two different "direct" axes (don't conflate):

  • Signal.impact_type (direct|indirect) = the article's relation to the queried node — epicenter (direct) vs ripple (indirect). Set by news(megatrend=…, impact="indirect").
  • Entity.direct (True|False) = whether that entity is factually mentioned in the article (True) vs impact-only / not named (False).

Narrow the feed by entity — server-side. news() (and news_search()) filter by entity_type / only_scored / min_relevance in the API, so page.total stays the exact filtered count (no wasted paging). These keep the whole article — for an exact per-row cut, still post-filter the entities as above.

mdx.news(entity_type="commodity")                      # feed → only stories that move a commodity
mdx.news(entity_type="private")                        # only stories moving a private co (OpenAI, SpaceX)
mdx.news(only_scored=True)                              # drop mention-only articles (keep judged impact)
mdx.news(min_relevance=0.8)                             # only a strongly-relevant scored entity
mdx.news(megatrend="ai-power", entity_type="crypto")   # entity filters compose with megatrend scope
mdx.news_search("oil supply shock", entity_type="commodity")  # search supports entity_type too
mdx.news_by_tickers("NVDA.US")                          # a covered STOCK's news (direct + indirect)
mdx.megatrends("ai-power").off_coverage()              # private / off-coverage roster

Entity filters do not apply to impact="indirect" (the ripple feed) — the API returns 400 if you combine them. On news_by_tickers, the ticker set already scopes the entities.

Only entities with a scored impact (many are mentioned-only) — only_scored=True narrows to such articles server-side; then read the scored entities off each signal:

scored = [e for s in mdx.news(megatrend="ai-power", only_scored=True)
          for e in s.entities if e.impact and e.impact.aspects]

stock(t).news() is a stock-centric timeline — a StockNews (the stock's own impact /trend/ relevance), not an entity graph (no entities[]). For the full graph of an article, use news().

Story-collapse (on by default). The same story is often republished / rewritten across outlets. news(), news_search() and news_by_tickers() merge those near-duplicates into a single signal by default (cosine-similarity grouping, server-side) so a feed reads one-story-one-row. Pass collapse=False when you want the raw, un-deduped stream — e.g. to measure coverage volume:

merged = mdx.news(megatrend="ai-power").to_list()                 # deduped (default)
raw    = mdx.news(megatrend="ai-power", collapse=False).to_list() # every republication

Theme brief — the whole picture in one call

mdx.theme(id).summary(...) (a theme = a megatrend node; also mdx.megatrends(id).summary(...)) returns a pre-composed analyst brief so you don't stitch 5+ requests together. It's a fixed composite dict, not a paginated list:

brief = mdx.theme("ai-power").summary(window="30d")     # 7d/30d/90d/180d/1y or mtd/qtd/ytd (or from_/to)
brief["pulse"]          # story_count, net_direction, pos/neg share + a `series` (volume+sentiment/bucket)
brief["top_stories"]    # epicenter, deduped; market-wraps & no-member-named stories deprioritized
brief["ripple"]         # indirect (ripple-in) stories, each with `via`
brief["winners"], brief["losers"]   # member stocks by net direction
brief["aspect_heatmap"] # which channels the theme is playing out through
brief["top_entities"]   # operating companies most in the news
brief["top_assets"]     # commodity / forex / crypto the theme moves (split out from companies)

Every count is story-deduped (20 outlets on one story = 1). The pulse.series is the momentum signal — there's no single momentum scalar (the latest bucket is the current, partial period). Cost: 15 credits.

Metering & errors

Every call carries X-Credits-Charged / X-RateLimit-*; check your balance any time (free, unmetered):

mdx.account()   # {'plan': …, 'credits': {'balance', 'daily_quota', 'resets_at', 'unlimited'}, 'rate_limit': …}
from marketdx.errors import QuotaError, RateLimitError

try:
    signals = mdx.news(megatrend="ai-power").to_list()
except RateLimitError as e:
    time.sleep(e.retry_after or 1)
except QuotaError:
    ...   # daily quota spent — resets 00:00 UTC

Enum values (aspect, direction, entity_type, …) are type hints for your editor — the API is the source of truth, so new values work without upgrading the SDK. The live list: mdx.enums().

Reference

news · news_search · news_types · megatrends (.stocks / .off_coverage) · gics (.stocks) · stocks (search + screener) · stock (.news / .competitors / .peers) · enums · account. Full API docs: marketdx.lab.ai.

License

MIT. Built by MarketDXdemocratizing financial data.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

marketdx-0.5.1.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

marketdx-0.5.1-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file marketdx-0.5.1.tar.gz.

File metadata

  • Download URL: marketdx-0.5.1.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for marketdx-0.5.1.tar.gz
Algorithm Hash digest
SHA256 2c745d54a867db0374ab9107a421d338e9d99c2def6fd7afe99ec72715099886
MD5 55ae7647550f0115e017d12760cab448
BLAKE2b-256 f80ddc12825f5233ab1fc1bb51bf0a84a50b9ba69854d640c4a73c38359aada1

See more details on using hashes here.

File details

Details for the file marketdx-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: marketdx-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 21.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for marketdx-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e7622e49338cf0b36b580d25baa62374d3f7047ed1bc67bdb653b370fa4df956
MD5 f2c85bb12583d75c2b047ef9166816fc
BLAKE2b-256 6a79f646feb068fccd33c4dfa644f92f4088277e96aeb7c2efbc6a8197d02176

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page