# Market Signals (`publicmoney/market-signals-mini`) Actor

One record per instrument, merged from five sources: equity and crypto quotes, news, crypto market data and on-chain balances, with the price source and how far the sources disagreed. Export data, run via API, schedule and monitor runs, or integrate with other tools.

- **URL**: https://apify.com/publicmoney/market-signals-mini.md
- **Developed by:** [Public Money](https://apify.com/publicmoney) (Apify)
- **Categories:** Business
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $6.00 / 1,000 records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Answering "what is going on with this" usually means five API calls, five schemas and a merge you wrote yourself. This Actor does it in one: pass tickers, coin ids and wallet addresses in the same list and get one flat record per instrument with quotes, news, crypto market data and on-chain balances, plus the price spread between the sources that disagreed and a per-signal status so you know what actually landed.

### What it does

- Takes **mixed inputs in one list**: a ticker, an index, an FX pair, a coin id or a wallet address, and classifies each one for you.
- Merges **five sources** into one record: Yahoo Finance and Google Finance for quotes, CoinGecko and CoinMarketCap for crypto, and block explorers for on-chain balances.
- Reports **which source the price came from** in `priceSource` and **how far the sources disagreed** in `priceSpreadPercent`, so a cross-checked price is visible rather than assumed.
- Carries a **per-signal status** in `sources`, so a record where news failed but the quote succeeded is honest about it instead of looking complete.
- Lets you **turn signals off**. Fewer signals means fewer child runs, so a quote-only run is faster and cheaper than the full sweep.
- Never fails the run on a child failure. A broken source is reported in `sources` and the rest of the record still ships.

### Use cases

| You need to | How this Actor does it |
| --- | --- |
| Answer "what is going on with X" | Pass one instrument, read one record |
| Cross-check a price | Read `priceSource` and `priceSpreadPercent` instead of trusting one feed |
| Cover a mixed portfolio | Put equities, coins and wallet addresses in the same list |
| Give an agent one tool instead of five | Call this over MCP and let the model ask about anything |
| Cut cost on a big run | Turn off the signals you do not need and watch the child runs drop |
| Build a daily briefing | Schedule the full sweep and render the dataset |

### Quick start

1. Click **Try for free**.
2. Add what you want to research, one per line, mixed freely: `AAPL`, `^GSPC`, `EURUSD=X`, `bitcoin`, `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`.
3. Pick your **Signals**. The default is quotes, news, crypto market data and on-chain. Crowd sentiment and price history each add a request per instrument.
4. Set **News per instrument** if the news signal is on.
5. Click **Start**. Rows appear within seconds.
6. Export as JSON, CSV, Excel or XML, or read the dataset over the API.

### Input

| Field | Type | Default | What it controls |
| --- | --- | --- | --- |
| `instruments` | array | `AAPL` | Tickers, coin ids or wallet addresses, mixed freely. Each is classified automatically |
| `signals` | array | quote, news, cryptoMarket, onchain | Which blocks to gather. Also available: `sentiment` and `history` |
| `newsPerInstrument` | integer | `5` | Stories per instrument when the news signal is on |
| `maxItems` | integer | `0` | Caps how many instrument records are written. `0` writes one per instrument |

```json
{
    "instruments": [
        "AAPL",
        "bitcoin",
        "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    ],
    "signals": [
        "quote",
        "news",
        "cryptoMarket",
        "onchain"
    ],
    "newsPerInstrument": 5
}
```

### Output

One dataset item per instrument, whatever kind it is. Source-specific fields are nested under the source that produced them, so `yahooFinance.peRatio` and `coingecko.ath` never collide. The dataset has four views: all instruments, stocks, coins and on-chain.

| Field group | Fields |
| --- | --- |
| Always | `status`, `instrument`, `kind`, `name`, `value`, `changePercent`, `currency` |
| Provenance | `priceSource`, `priceValidFrom`, `priceSpreadPercent`, `changeWindow`, `sources` |
| Equities | `yahooFinance.peRatio`, `yahooFinance.eps`, `yahooFinance.earningsDate`, `googleFinance.analystConsensus`, `googleFinance.analystPriceTargetAverage` |
| Crypto | `coingecko.marketCapRank`, `coingecko.volume24h`, `coingecko.ath`, `coinmarketcap.dominance`, `coinmarketcap.percentChange7d` |
| On-chain | `onchain.address`, `onchain.ensDomainName`, `onchain.nativeBalance`, `onchain.transactionCount`, `onchain.isContract` |
| Optional signals | `news`, `sentiment`, `priceHistory` |

```json
{
    "status": "ok",
    "instrument": "AAPL",
    "kind": "equity",
    "name": "Apple Inc.",
    "value": 319.97,
    "changePercent": -2.51,
    "currency": "USD",
    "priceSource": "yahooFinance",
    "priceSpreadPercent": 0.02,
    "priceValidFrom": "2026-09-04T20:00:01.000Z",
    "sources": {
        "yahooFinance": "ok",
        "googleFinance": "ok",
        "coingecko": "notRequested",
        "onchain": "notRequested"
    },
    "yahooFinance": {
        "peRatio": 36.65,
        "eps": 8.73,
        "earningsDate": "Oct 29, 2026"
    },
    "googleFinance": {
        "analystConsensus": "Buy",
        "analystPriceTargetAverage": 352.18
    }
}
```

### Integrations

Run it over the API and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/publicmoney~market-signals-mini/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instruments": ["AAPL", "bitcoin", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"], "signals": ["quote", "news", "cryptoMarket", "onchain"], "newsPerInstrument": 5}'
```

From Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("publicmoney/market-signals-mini").call(run_input={"instruments": ["AAPL", "bitcoin", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"], "signals": ["quote", "news", "cryptoMarket", "onchain"], "newsPerInstrument": 5})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["value"])
```

Give an AI agent the Actor over MCP:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com/?actors=publicmoney/market-signals-mini"
        }
    }
}
```

Schedules run it on any cron, webhooks fire when a run finishes, and platform integrations push the
dataset to Google Sheets, Slack, Airtable, Zapier or your own endpoint.

### Cost

Pay per event, so you pay for records rather than compute time.

| Event | Free tier | Top volume tier |
| --- | --- | --- |
| Instrument record | $0.01 | $0.004 |
| Actor start | $0.00005 per GB | Same |

Two things are charged, and it is worth being explicit about the second. The **instrument record** above is this Actor's own event. On top of that, this Actor runs the Yahoo Finance, Google Finance, CoinGecko, CoinMarketCap and Blockchain Scanner Actors as **child runs on your account**, and each one charges its own per-record price. So the true cost of a full sweep is this Actor's record plus the records its children produced, which will not appear in this Actor's own usage total. Turning signals off is the lever: a quote-only run starts two children instead of five. A record that returned no data is published as a failure row and is never charged.

### Troubleshooting

| Issue | Solution |
| --- | --- |
| A record has data but `sources` shows a failure | That is the design. A child Actor that failed is reported per signal and the rest of the record still ships, so read `sources` before treating a record as complete. |
| An instrument was classified as the wrong kind | Classification is by shape. A bare word that is both a ticker and a coin id is ambiguous, so disambiguate with a suffix: `AAPL:NASDAQ` for the equity, a full coin id for the coin. |
| The run costs more than the record price suggests | The child Actors charge their own per-record price on your account, and those charges are not in this Actor's usage total. Turn off signals you do not need. |
| `priceSpreadPercent` is large | The sources genuinely disagreed, usually because their timestamps differ. Read `priceValidFrom` and `priceSource` before acting on it. |
| The run is slower than the single-source Actors | It starts child runs and waits for them, so a full sweep takes minutes rather than seconds. Cut signals or split the list. |
| An on-chain address returned nothing | The chain was not inferred from the address shape, or the address has no activity. Use the Blockchain Scanner Actor to pin the chain. |

### FAQ

#### What does this do that the single-source Actors do not?

It merges them. One flat record per instrument instead of five datasets to join, plus provenance they cannot give you: which source the price came from and how far they disagreed.

#### Why is it priced above the other Actors in this fleet?

Because one record fans out into several child runs. The record itself is $0.01 on the free tier, and the child Actors charge their own per-record price on your account on top of that. The cost section above spells this out.

#### Which sources does it read?

Yahoo Finance and Google Finance for quotes and news, CoinGecko and CoinMarketCap for crypto, and block explorers for on-chain balances. Each is a separate Actor in this fleet.

#### Can I mix stocks, coins and wallets in one run?

Yes, and that is the point. Each input is classified by shape, and `kind` tells you how it was read.

#### How do I make it cheaper?

Turn signals off. A quote-only run starts two child runs instead of five, so the child charges fall with it. If you only need one source, run that source's Actor directly.

#### Do I need a the sources it reads API key?

No. There is no key for any of the five sources. You need an Apify token to call the Actor over the API, and the child Actors run on your own account.

#### Can I get this data in Python?

Yes, with the `apify-client` package as shown above. It returns parsed JSON, so there is no HTML or response handling on your side.

#### Can I get the data into Excel or Google Sheets?

Yes. Export the dataset as XLSX or CSV, or connect the Google Sheets integration so each run appends to a sheet.

#### Can an AI agent call this Actor?

Yes. Add it to an MCP client with the config above and the model can request what it needs on its own. Every record is flat JSON with named fields, so no post-processing is needed.

#### Is it legal to use this data?

Every source behind this Actor is public and needs no login, and no personal data is collected beyond the pseudonymous addresses you pass in yourself. How you store, redistribute or act on market data is governed by your own agreements and local rules. Take your own legal advice for your use case.

### Changelog

- **0.0.2** Added the price spread across sources, per-signal status, crowd sentiment and OHLC history.
- **0.0.1** First release. Quotes, news, crypto market data and on-chain balances in one record.

### Feedback

Found a source that should be in the merge, or an instrument that was classified as the wrong kind? Open an issue on the Issues tab with the input and what you expected. A daily test runs every Actor in the fleet against live sources, so fixes ship fast.

# Actor input Schema

## `instruments` (type: `array`):

What to research, one per line, mixed freely: a ticker ('AAPL', 'BRK-B', '^GSPC', 'EURUSD=X', 'AAPL:NASDAQ'), a coin ID or slug ('bitcoin', 'solana'), a wallet or token address ('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', a Bitcoin or Solana address), or the URL of a Yahoo Finance, Google Finance, CoinGecko, CoinMarketCap or block explorer page. Upper-case short entries are read as tickers, lower-case slugs as coins, and an explorer URL also names its chain.

## `signals` (type: `array`):

Which blocks of data to gather. Each signal runs one or more child Actors on your account, so fewer signals means fewer child runs and a cheaper, faster answer. Crowd sentiment and price history each add one request per instrument on top. Examples: 'quote', 'news', 'cryptoMarket', 'onchain', 'sentiment', 'history'. Default is 'quote', 'news', 'cryptoMarket', 'onchain'.

## `newsPerInstrument` (type: `integer`):

How many stories to keep per instrument when the news signal is on. News is gathered by a child Actor run, so a larger value costs more on that child rather than on this Actor. Ignored when news is off. Examples: 3, 5, 20. Default is 5.

## `maxItems` (type: `integer`):

Maximum number of instruments to read, counted from the top of the list. Use it to cap spend on a long list without editing the list itself. Examples: 10, 50, 200. Default is 0, which reads every instrument given.

## Actor input object example

```json
{
  "instruments": [
    "AAPL",
    "bitcoin",
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
  ],
  "signals": [
    "quote",
    "news",
    "cryptoMarket",
    "onchain"
  ],
  "newsPerInstrument": 5,
  "maxItems": 0
}
```

# Actor output Schema

## `results` (type: `string`):

One merged record per instrument, in the default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "instruments": [
        "AAPL",
        "bitcoin",
        "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    ],
    "signals": [
        "quote",
        "news",
        "cryptoMarket",
        "onchain"
    ],
    "newsPerInstrument": 5,
    "maxItems": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicmoney/market-signals-mini").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "instruments": [
        "AAPL",
        "bitcoin",
        "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    ],
    "signals": [
        "quote",
        "news",
        "cryptoMarket",
        "onchain",
    ],
    "newsPerInstrument": 5,
    "maxItems": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("publicmoney/market-signals-mini").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "instruments": [
    "AAPL",
    "bitcoin",
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
  ],
  "signals": [
    "quote",
    "news",
    "cryptoMarket",
    "onchain"
  ],
  "newsPerInstrument": 5,
  "maxItems": 0
}' |
apify call publicmoney/market-signals-mini --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,publicmoney/market-signals-mini"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CqdM7YyOy6FFvA62G/builds/tGG8H6u3OMvekRhtm/openapi.json
