Financial market screening with pluggable rules and alerts
Project description
finwatch
Financial market screening with pluggable rules and alerts.
Screen stocks, crypto, commodities, or any Yahoo Finance-supported asset against technical rules. Get notified via Telegram (or your own alert channel) when conditions are met.
Installation
pip install finwatch
# or with uv
uv add finwatch
Quick start
from finwatch import Watcher
from finwatch.retrievers.yahoo import YahooPriceRetriever
from finwatch.rules.rsi import RSIRule, RSIDirection
watcher = Watcher(
retriever=YahooPriceRetriever(),
rules=[RSIRule(threshold=30, direction=RSIDirection.BELOW)],
alerts=[],
period="3mo",
)
results = watcher.run(["AAPL", "TSLA", "BTC-USD", "ETH-USD", "GC=F"])
for r in results:
status = "TRIGGERED" if r.triggered else "ok"
print(f"[{status}] {r.symbol}")
for rr in r.rule_results:
print(f" {rr.message}")
Multi-rule screening with Telegram alerts
import os
from finwatch import Watcher
from finwatch.retrievers.yahoo import YahooPriceRetriever
from finwatch.rules.rsi import RSIRule, RSIDirection
from finwatch.alerts.telegram import TelegramAlert
watcher = Watcher(
retriever=YahooPriceRetriever(),
rules=[
RSIRule(threshold=30, direction=RSIDirection.BELOW), # oversold
RSIRule(threshold=70, direction=RSIDirection.ABOVE), # overbought
],
alerts=[
TelegramAlert(
token=os.environ["TELEGRAM_TOKEN"],
chat_id=os.environ["TELEGRAM_CHAT_ID"],
)
],
period="3mo",
)
results = watcher.run(["AAPL", "TSLA", "MSFT", "BTC-USD", "ETH-USD"])
triggered = [r for r in results if r.triggered]
print(f"Screened {len(results)} assets — {len(triggered)} triggered.")
Each symbol is evaluated against all rules. ScreenResult.triggered is True if any rule fires. Inspect result.rule_results for per-rule detail.
Architecture
symbols
└─▶ PriceRetriever.fetch() ─▶ list[PriceBar]
│
Rule.evaluate() (×N rules)
│
list[RuleResult]
│
Watcher assembles ─▶ list[ScreenResult]
│
triggered results ─▶ Alert.send()
Extending finwatch
Custom PriceRetriever
from finwatch.retrievers.base import PriceRetriever
from finwatch.models import PriceBar
class MyRetriever(PriceRetriever):
def fetch(self, symbol: str, period: str = "3mo") -> list[PriceBar]:
# fetch from your data source
...
Custom Rule
from finwatch.rules.base import Rule
from finwatch.models import PriceBar, RuleResult
class MyRule(Rule):
@property
def name(self) -> str:
return "MyRule"
def evaluate(self, symbol: str, bars: list[PriceBar]) -> RuleResult:
# compute indicator, return RuleResult
...
For indicator math, add a pure function to finwatch/indicators/ and import it in your rule.
Custom Alert
from finwatch.alerts.base import Alert
from finwatch.models import ScreenResult
class MyAlert(Alert):
async def send(self, results: list[ScreenResult]) -> None:
for r in results:
if r.triggered:
# send email, Slack, webhook, etc.
...
Environment variables
| Variable | Description |
|---|---|
TELEGRAM_TOKEN |
Bot API token from @BotFather |
TELEGRAM_CHAT_ID |
Target chat ID or channel username |
Development
uv sync --all-extras
# Lint + format
ruff check . --fix && ruff format .
# Type check
mypy src/
# Tests
pytest --tb=short
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file finwatch-0.1.0.tar.gz.
File metadata
- Download URL: finwatch-0.1.0.tar.gz
- Upload date:
- Size: 6.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86fd5a58746d268c0cbcdbce2e34bd732c85774df7d506879d4f391fe2e3f627
|
|
| MD5 |
df06fa045938221f5ab26da70ba46a1d
|
|
| BLAKE2b-256 |
01c368abf46dc9828e0b66f054ad1982cab4dd2eea63f9250da871ba0793252e
|
Provenance
The following attestation bundles were made for finwatch-0.1.0.tar.gz:
Publisher:
release.yml on winsonsutanto10/finwatch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
finwatch-0.1.0.tar.gz -
Subject digest:
86fd5a58746d268c0cbcdbce2e34bd732c85774df7d506879d4f391fe2e3f627 - Sigstore transparency entry: 1677863479
- Sigstore integration time:
-
Permalink:
winsonsutanto10/finwatch@883956ec5bb67d83f08b6bd0f72b33dff9c1b689 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/winsonsutanto10
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@883956ec5bb67d83f08b6bd0f72b33dff9c1b689 -
Trigger Event:
release
-
Statement type:
File details
Details for the file finwatch-0.1.0-py3-none-any.whl.
File metadata
- Download URL: finwatch-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
636cd9cd8c843757cd5ccca8d1d35fe9b72f33f7c1985aedd053a199fc76cf3d
|
|
| MD5 |
ddc37d299dc5d45c0d7e04cc4dec4a56
|
|
| BLAKE2b-256 |
4b777a8bc194d5f25b4adca6900aa0eb754a6a4d79757211a13530ad327243be
|
Provenance
The following attestation bundles were made for finwatch-0.1.0-py3-none-any.whl:
Publisher:
release.yml on winsonsutanto10/finwatch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
finwatch-0.1.0-py3-none-any.whl -
Subject digest:
636cd9cd8c843757cd5ccca8d1d35fe9b72f33f7c1985aedd053a199fc76cf3d - Sigstore transparency entry: 1677863548
- Sigstore integration time:
-
Permalink:
winsonsutanto10/finwatch@883956ec5bb67d83f08b6bd0f72b33dff9c1b689 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/winsonsutanto10
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@883956ec5bb67d83f08b6bd0f72b33dff9c1b689 -
Trigger Event:
release
-
Statement type: