Professional Bun + TypeScript CLI for eToro portfolio inspection, technical analysis, watchlist scanning, daily reports, and guarded trading previews with explicit safety rails
███████╗████████╗ ██████╗ ██████╗ ██████╗
██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗██╔═══██╗
█████╗ ██║ ██║ ██║██████╔╝██║ ██║
██╔══╝ ██║ ██║ ██║██╔══██╗██║ ██║
███████╗ ██║ ╚██████╔╝██║ ██║╚██████╔╝
╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝
A Bun + TypeScript command-line tool for inspecting your eToro account, reading portfolio data, analyzing positions with technical indicators, scanning watchlists, checking active orders, and preparing trading orders with explicit safety rails.
This project is intentionally structured with Clean Architecture and the Repository Pattern:
src/
domain/ Entities, repository contracts, indicators and scoring rules.
application/ Use cases: portfolio, balance, orders, analysis, watchlist, daily report, trading preview.
infrastructure/ HTTP client and concrete eToro/Massive repositories.
commands/ CLI adapters. Parse arguments and call application use cases.
ui/ Banner, tables, colors and formatting.
This project does not use Python or .venv.
bun install
cp .env.example .env
Fill .env:
ETORO_PUBLIC_KEY=your_public_key
ETORO_API_PRIVATE_KEY=your_user_key
ETORO_ENVIRONMENT=real
MASSIVE_API_KEY=optional
ETORO_DEFAULT_RESOLUTION=D
ETORO_DEFAULT_LOOKBACK_DAYS=250
ETORO_ENABLE_REAL_TRADING=false
Run locally:
bun run index.ts help
Install as a local global command:
bun link
etoro help
After running bun link, the etoro command is available outside this project folder.
The CLI reads configuration from environment variables. If you run etoro globally, make sure those variables are available in your shell.
Temporary exports for the current terminal session:
export ETORO_PUBLIC_KEY="your_public_key"
export ETORO_API_PRIVATE_KEY="your_user_key"
export ETORO_ENVIRONMENT="real"
export ETORO_DEFAULT_RESOLUTION="D"
export ETORO_DEFAULT_LOOKBACK_DAYS="250"
export ETORO_ENABLE_REAL_TRADING="false"
Then validate:
etoro health
Permanent exports for zsh:
nano ~/.zshrc
Add:
export ETORO_PUBLIC_KEY="your_public_key"
export ETORO_API_PRIVATE_KEY="your_user_key"
export ETORO_ENVIRONMENT="real"
export ETORO_DEFAULT_RESOLUTION="D"
export ETORO_DEFAULT_LOOKBACK_DAYS="250"
export ETORO_ENABLE_REAL_TRADING="false"
Reload your shell:
source ~/.zshrc
etoro health
Recommended safety practice: keep ETORO_ENABLE_REAL_TRADING=false globally. For a single real trading command, enable it inline:
ETORO_ENABLE_REAL_TRADING=true etoro buy TSLA \
--amount 10 \
--limit-price 420 \
--stop-loss-rate 350 \
--take-profit-rate 500 \
--confirm-real \
--i-understand-real-money
bun run index.ts health
bun run index.ts whoami
bun run index.ts balance
bun run index.ts portfolio
bun run index.ts orders
bun run index.ts analyze
bun run index.ts symbol TSLA
bun run index.ts watchlist --symbols TSLA,AAPL,NVDA --provider etoro
bun run index.ts daily
If you ran bun link, replace bun run index.ts with etoro.
| Command | Description |
|---|---|
etoro help | Shows the logo and available commands. |
etoro health | Validates environment variables and eToro API connectivity. |
etoro whoami | Shows session identifiers such as GCID, Real CID and Demo CID. |
etoro balance | Shows available cash, estimated equity, invested amount, market value and unrealized PnL. |
etoro portfolio | Lists portfolio positions with prices, PnL and return. |
etoro orders | Lists active or pending orders from the P&L endpoint. |
etoro analyze | Runs technical analysis for every open portfolio position. |
etoro symbol TSLA | Runs technical analysis for one portfolio position. |
etoro watchlist --symbols TSLA,AAPL --provider etoro | Scans symbols using eToro market data. |
etoro watchlist --symbols TSLA,AAPL --provider massive | Scans symbols using Massive, if MASSIVE_API_KEY is configured. |
etoro daily | Shows portfolio, technical readings and alerts. |
etoro buy ... | Prepares or sends buy orders. Dry-run unless all real-trading safety flags are present. |
etoro sell ... | Dry-run only in this MVP. Real selling requires close-by-position support. |
Useful options:
etoro analyze --resolution D --candles 250
etoro symbol NVDA --resolution D --candles 250
etoro watchlist --symbols TSLA,NVDA,AMZN --provider etoro --resolution D --candles 250
etoro daily --candles 250
The analysis is calculated locally in TypeScript. eToro provides market data and historical candles; the CLI calculates indicators and applies local scoring rules.
Indicators:
| Indicator | Purpose |
|---|---|
SMA200 | Main trend filter. |
EMA20 / EMA50 | Momentum filter. |
RSI14 | Overbought / oversold conditions. |
MACD histogram | Trend continuation confirmation. |
ATR14 | Volatility context. |
Volume vs 20-period average | Entry confirmation. |
The interpretation logic lives in:
src/domain/scoring.ts
Use:
etoro orders
This command only performs a GET request. It reads active order collections returned by:
GET /api/v1/trading/info/real/pnl
GET /api/v1/trading/info/demo/pnl
Collections inspected:
orders
stockOrders
entryOrders
exitOrders
ordersForOpen
ordersForClose
ordersForCloseMultiple
Real trading is disabled by default.
To execute a real buy order, all of these must be true:
ETORO_ENABLE_REAL_TRADING=true
--confirm-real
--i-understand-real-money
Without those conditions, buy only prints a dry-run preview and the planned eToro payload.
Dry-run, no real order:
ETORO_ENABLE_REAL_TRADING=false etoro buy TSLA \
--amount 10 \
--limit-price 420 \
--stop-loss-rate 350 \
--take-profit-rate 500 \
--confirm-real \
--i-understand-real-money
Real order, only if you intentionally enabled real trading:
etoro buy TSLA \
--amount 10 \
--limit-price 420 \
--stop-loss-rate 350 \
--take-profit-rate 500 \
--confirm-real \
--i-understand-real-money
The CLI will build a payload like:
{
"InstrumentID": 1111,
"IsBuy": true,
"Leverage": 1,
"Rate": 420,
"Amount": 10,
"StopLossRate": 350,
"IsNoStopLoss": false,
"TakeProfitRate": 500,
"IsNoTakeProfit": false
}
Implemented in the infrastructure layer:
| Operation | Endpoint |
|---|---|
| Real market buy by amount | POST /trading/execution/market-open-orders/by-amount |
| Demo market buy by amount | POST /trading/execution/demo/market-open-orders/by-amount |
| Real market buy by units | POST /trading/execution/market-open-orders/by-units |
| Demo market buy by units | POST /trading/execution/demo/market-open-orders/by-units |
| Real limit order | POST /trading/execution/limit-orders |
| Demo limit order | POST /trading/execution/demo/limit-orders |
| Real close position | POST /trading/execution/market-close-orders/positions/{positionId} |
| Demo close position | POST /trading/execution/demo/market-close-orders/positions/{positionId} |
sell remains dry-run in the CLI because safe selling should close by positionId, not only by symbol.
Type-check:
bun run typecheck
Run a command locally:
bun run index.ts portfolio
Check Git status:
git status --short
.env.ETORO_ENVIRONMENT=demo when possible.