Imported from cbh4ou/btc-2yr-dca (
AGENTS.md). Install upstream withnpx skills add cbh4ou/btc-2yr-dca. Copyright stays with the author.
Bitcoin DCA Bot - Agent Knowledge Base
Project: bitcoin-dca-accumulation-bot
Stack: Python 3.13+, CCXT, pandas, numpy
Package Manager: uv - use uv run for all Python commands
Generated: 2026-02-08
OVERVIEW
Automated Bitcoin accumulation bot using the 2-Year Moving Average Multiplier strategy. Buys BTC on a schedule when price is below calculated thresholds (Green Line = 730-day SMA, Red Line = 5x multiplier).
STRUCTURE
.
├── src/btc_dca_bot/ # Main package (7 modules, ~900 LOC)
│ ├── main.py # Entry point + DCABot orchestration
│ ├── strategy.py # MAMultiplierStrategy + signals
│ ├── exchange.py # CCXT wrapper with retry logic
│ ├── data_fetcher.py # Abstract + CCXT + CSV fetchers
│ ├── state.py # PortfolioState persistence
│ └── logger.py # DashboardLogger with ASCII UI
├── tests/ # pytest suite (7 files)
├── test_data/ # Mock CSV data for testing
├── data/ # Runtime state persistence
└── openspec/ # Change management specs
WHERE TO LOOK
| Task | Location | Notes |
|---|---|---|
| Entry point | src/btc_dca_bot/main.py |
DCABot.run() heartbeat loop |
| Strategy logic | src/btc_dca_bot/strategy.py |
730-day SMA, 5x multiplier |
| Exchange API | src/btc_dca_bot/exchange.py |
CCXT wrapper, exponential backoff |
| Data sources | src/btc_dca_bot/data_fetcher.py |
Factory pattern: CCXTDataFetcher / CSVDataFetcher |
| State persistence | src/btc_dca_bot/state.py |
Atomic JSON writes with tempfile |
| Logging/Dashboard | src/btc_dca_bot/logger.py |
Box-drawing ASCII dashboard |
| Tests | tests/test_*.py |
pytest, pytest-asyncio |
CODE MAP
| Symbol | Type | Location | Role |
|---|---|---|---|
DCABot |
class | main.py:22 | Main orchestrator with signal handling |
MAMultiplierStrategy |
class | strategy.py:28 | 2Y MA multiplier calculation |
StrategySignal |
dataclass | strategy.py:15 | Immutable signal output |
AccumulationZone |
Enum | strategy.py:7 | AGGRESSIVE / STANDARD / STOP |
ExchangeWrapper |
class | exchange.py:15 | CCXT wrapper with retry |
ExchangeError |
Exception | exchange.py:9 | Custom exchange errors |
DataFetcher |
ABC | data_fetcher.py:9 | Abstract data source |
PortfolioState |
dataclass | state.py:9 | Tracks trades + PnL |
DashboardLogger |
class | logger.py:11 | Structured logging + dashboard |
CONVENTIONS
Code Style (enforced by ruff):
- Line length: 100
- Google-style docstrings
- Strict mypy:
disallow_untyped_defs=true - No
E501(line too long) - handled by formatter
Type Safety:
- ALL functions must have type annotations
- Use
from __future__ import annotationsfor forward refs - Dataclasses for data containers
- Abstract base classes for extensible components
Error Handling:
- Custom
ExchangeErrorfor exchange failures - Exponential backoff with jitter in
ExchangeWrapper._execute_with_backoff() - Graceful shutdown on SIGINT/SIGTERM
State Management:
- Atomic file writes: write to temp →
os.replace() - State auto-saves after each trade
- JSON serialization in
data/portfolio_state.json
ANTI-PATTERNS (AVOID)
- Don't block the heartbeat - Always sleep between cycles
- Don't swallow exchange errors - Raise
ExchangeErrorafter retries exhausted - Don't use
floatfor money - Already using floats; document precision limits - Don't skip type annotations - mypy is strict, CI will fail
- Don't call
state.save()directly - Userecord_trade()which auto-saves
UNIQUE STYLES
Factory Pattern for Data Sources:
fetcher = create_data_fetcher(exchange_id="coinbase") # Live
fetcher = create_data_fetcher(csv_path="./test_data/mock.csv") # Mock
Environment-Driven Configuration:
- All config via env vars (no config files)
MOCK_DATA_CSVpresence triggers mock mode- Exchange credentials only required for live mode
Dashboard Output:
- ASCII box-drawing characters for status display
- Zone visualization: 🟢 AGGRESSIVE / 🟡 STANDARD / 🔴 STOP
COMMANDS
# Run with mock data (no API keys)
MOCK_DATA_CSV=./test_data/test_zones.csv TEST_MODE=true uv run python -m btc_dca_bot.main
# Run with live exchange
uv run python -m btc_dca_bot.main
# Run tests
uv run pytest
# Type checking
uv run mypy src/btc_dca_bot
# Linting
uv run ruff check .
uv run ruff format .
# Docker
docker-compose up -d
docker-compose logs -f
NOTES
- Testing: Uses pytest-asyncio. Mock CSV data in
test_data/for zone testing. - Exchange Support: Any CCXT-supported exchange. Tested with Coinbase.
- Precision: Float math for BTC amounts; sufficient for retail DCA.
- Deployment: Docker Compose with volume mounts for state/logs.
- No CI/CD: No
.github/workflows/- run tests locally before deploying.
<skills_system priority="1">
Available Skills
How to use skills:
- Invoke:
npx openskills read <skill-name>(run in your shell)- For multiple:
npx openskills read skill-one,skill-two
- For multiple:
- The skill content will load with detailed instructions on how to complete the task
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
Usage notes:
- Only use skills listed in <available_skills> below
- Do not invoke a skill that is already loaded in your context
- Each skill invocation is stateless
<available_skills>
</available_skills>
</skills_system>