summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 15:56:35 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 15:56:35 +0900
commit33b14aaa2344b0fd95d1629627c3d135b24ae102 (patch)
tree90b214758bc3b076baa7711226a1a1be6268e72e /cli
parent9360f1a800aa29b40399a2f3bfbfcf215a04e279 (diff)
feat: initial trading platform implementation
Binance spot crypto trading platform with microservices architecture: - shared: Pydantic models, Redis Streams broker, asyncpg DB layer - data-collector: Binance WebSocket/REST market data collection - strategy-engine: Plugin-based strategy execution (RSI, Grid) - order-executor: Order execution with risk management - portfolio-manager: Position tracking and PnL calculation - backtester: Historical strategy testing with simulator - cli: Click-based CLI for all operations - Docker Compose orchestration with Redis and PostgreSQL - 24 test files covering all modules
Diffstat (limited to 'cli')
-rw-r--r--cli/pyproject.toml19
-rw-r--r--cli/src/trading_cli/__init__.py0
-rw-r--r--cli/src/trading_cli/commands/__init__.py0
-rw-r--r--cli/src/trading_cli/commands/backtest.py26
-rw-r--r--cli/src/trading_cli/commands/data.py31
-rw-r--r--cli/src/trading_cli/commands/portfolio.py20
-rw-r--r--cli/src/trading_cli/commands/service.py29
-rw-r--r--cli/src/trading_cli/commands/strategy.py20
-rw-r--r--cli/src/trading_cli/commands/trade.py35
-rw-r--r--cli/src/trading_cli/main.py22
-rw-r--r--cli/tests/__init__.py0
-rw-r--r--cli/tests/test_cli_data.py17
-rw-r--r--cli/tests/test_cli_trade.py10
13 files changed, 229 insertions, 0 deletions
diff --git a/cli/pyproject.toml b/cli/pyproject.toml
new file mode 100644
index 0000000..e208021
--- /dev/null
+++ b/cli/pyproject.toml
@@ -0,0 +1,19 @@
+[project]
+name = "trading-cli"
+version = "0.1.0"
+description = "CLI interface for the trading platform"
+requires-python = ">=3.12"
+dependencies = ["click>=8.0", "rich>=13.0", "trading-shared"]
+
+[project.scripts]
+trading = "trading_cli.main:cli"
+
+[project.optional-dependencies]
+dev = ["pytest>=8.0", "pytest-asyncio>=0.23"]
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[tool.hatch.build.targets.wheel]
+packages = ["src/trading_cli"]
diff --git a/cli/src/trading_cli/__init__.py b/cli/src/trading_cli/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cli/src/trading_cli/__init__.py
diff --git a/cli/src/trading_cli/commands/__init__.py b/cli/src/trading_cli/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cli/src/trading_cli/commands/__init__.py
diff --git a/cli/src/trading_cli/commands/backtest.py b/cli/src/trading_cli/commands/backtest.py
new file mode 100644
index 0000000..40617b6
--- /dev/null
+++ b/cli/src/trading_cli/commands/backtest.py
@@ -0,0 +1,26 @@
+import click
+
+
+@click.group()
+def backtest():
+ """Backtesting commands."""
+ pass
+
+
+@backtest.command()
+@click.option("--strategy", required=True, help="Strategy name to backtest")
+@click.option("--symbol", required=True, help="Trading symbol (e.g. BTCUSDT)")
+@click.option("--from", "from_date", required=True, help="Start date (ISO format)")
+@click.option("--to", "to_date", default=None, help="End date (ISO format, defaults to now)")
+@click.option("--balance", default=10000.0, show_default=True, help="Initial balance in USDT")
+def run(strategy, symbol, from_date, to_date, balance):
+ """Run a backtest for a strategy."""
+ to_label = to_date or "now"
+ click.echo(f"Running backtest: strategy={strategy}, symbol={symbol}, {from_date} → {to_label}, balance={balance}...")
+
+
+@backtest.command()
+@click.option("--id", "backtest_id", required=True, help="Backtest run ID")
+def report(backtest_id):
+ """Show a backtest report by ID."""
+ click.echo(f"Showing backtest report for ID: {backtest_id}...")
diff --git a/cli/src/trading_cli/commands/data.py b/cli/src/trading_cli/commands/data.py
new file mode 100644
index 0000000..1fa5e30
--- /dev/null
+++ b/cli/src/trading_cli/commands/data.py
@@ -0,0 +1,31 @@
+import click
+
+
+@click.group()
+def data():
+ """Data collection and management commands."""
+ pass
+
+
+@data.command()
+@click.option("--symbol", required=True, help="Trading symbol (e.g. BTCUSDT)")
+@click.option("--timeframe", default="1m", show_default=True, help="Candle timeframe")
+def collect(symbol, timeframe):
+ """Start collecting live market data for a symbol."""
+ click.echo(f"Starting data collection for {symbol} at {timeframe} timeframe...")
+
+
+@data.command()
+@click.option("--symbol", required=True, help="Trading symbol (e.g. BTCUSDT)")
+@click.option("--timeframe", default="1m", show_default=True, help="Candle timeframe")
+@click.option("--from", "since", default=None, help="Start date (ISO format)")
+@click.option("--limit", default=1000, show_default=True, help="Number of candles to fetch")
+def history(symbol, timeframe, since, limit):
+ """Download historical market data for a symbol."""
+ click.echo(f"Downloading {limit} {timeframe} candles for {symbol}" + (f" since {since}" if since else "") + "...")
+
+
+@data.command("list")
+def list_():
+ """List available data streams and symbols."""
+ click.echo("Fetching available data streams and collected symbols...")
diff --git a/cli/src/trading_cli/commands/portfolio.py b/cli/src/trading_cli/commands/portfolio.py
new file mode 100644
index 0000000..9389bac
--- /dev/null
+++ b/cli/src/trading_cli/commands/portfolio.py
@@ -0,0 +1,20 @@
+import click
+
+
+@click.group()
+def portfolio():
+ """Portfolio management commands."""
+ pass
+
+
+@portfolio.command()
+def show():
+ """Show the current portfolio holdings and balances."""
+ click.echo("Fetching current portfolio...")
+
+
+@portfolio.command()
+@click.option("--days", default=30, show_default=True, help="Number of days of history")
+def history(days):
+ """Show PnL history for the portfolio."""
+ click.echo(f"Fetching PnL history for the last {days} days...")
diff --git a/cli/src/trading_cli/commands/service.py b/cli/src/trading_cli/commands/service.py
new file mode 100644
index 0000000..d01eaae
--- /dev/null
+++ b/cli/src/trading_cli/commands/service.py
@@ -0,0 +1,29 @@
+import subprocess
+import click
+
+
+@click.group()
+def service():
+ """Docker service management commands."""
+ pass
+
+
+@service.command()
+def up():
+ """Start all services with docker compose."""
+ click.echo("Starting all services...")
+ subprocess.run(["docker", "compose", "up", "-d"], check=True)
+
+
+@service.command()
+def down():
+ """Stop all services with docker compose."""
+ click.echo("Stopping all services...")
+ subprocess.run(["docker", "compose", "down"], check=True)
+
+
+@service.command()
+@click.option("--name", required=True, help="Service name to follow logs for")
+def logs(name):
+ """Follow logs for a specific service."""
+ subprocess.run(["docker", "compose", "logs", "-f", name], check=True)
diff --git a/cli/src/trading_cli/commands/strategy.py b/cli/src/trading_cli/commands/strategy.py
new file mode 100644
index 0000000..68ffeee
--- /dev/null
+++ b/cli/src/trading_cli/commands/strategy.py
@@ -0,0 +1,20 @@
+import click
+
+
+@click.group()
+def strategy():
+ """Strategy management commands."""
+ pass
+
+
+@strategy.command("list")
+def list_():
+ """List all available trading strategies."""
+ click.echo("Fetching available strategies...")
+
+
+@strategy.command()
+@click.option("--name", required=True, help="Strategy name")
+def info(name):
+ """Show detailed information about a strategy."""
+ click.echo(f"Fetching details for strategy: {name}...")
diff --git a/cli/src/trading_cli/commands/trade.py b/cli/src/trading_cli/commands/trade.py
new file mode 100644
index 0000000..f90e0ed
--- /dev/null
+++ b/cli/src/trading_cli/commands/trade.py
@@ -0,0 +1,35 @@
+import click
+
+
+@click.group()
+def trade():
+ """Trading bot management commands."""
+ pass
+
+
+@trade.command()
+@click.option("--strategy", required=True, help="Strategy name to run")
+@click.option("--symbol", required=True, help="Trading symbol (e.g. BTCUSDT)")
+def start(strategy, symbol):
+ """Start a trading bot for a strategy and symbol."""
+ click.echo(f"Starting trading bot: strategy={strategy}, symbol={symbol}...")
+
+
+@trade.command()
+@click.option("--strategy", required=True, help="Strategy name to stop")
+def stop(strategy):
+ """Stop a running trading bot."""
+ click.echo(f"Stopping trading bot for strategy: {strategy}...")
+
+
+@trade.command()
+def status():
+ """Show status of all running trading bots."""
+ click.echo("Fetching running bots status...")
+
+
+@trade.command("stop-all")
+def stop_all():
+ """Stop all running trading bots."""
+ click.confirm("Are you sure you want to stop all running bots?", abort=True)
+ click.echo("Stopping all running trading bots...")
diff --git a/cli/src/trading_cli/main.py b/cli/src/trading_cli/main.py
new file mode 100644
index 0000000..db3c282
--- /dev/null
+++ b/cli/src/trading_cli/main.py
@@ -0,0 +1,22 @@
+import click
+from trading_cli.commands.data import data
+from trading_cli.commands.trade import trade
+from trading_cli.commands.backtest import backtest
+from trading_cli.commands.portfolio import portfolio
+from trading_cli.commands.strategy import strategy
+from trading_cli.commands.service import service
+
+
+@click.group()
+@click.version_option(version="0.1.0")
+def cli():
+ """Trading Platform CLI — Binance spot crypto trading"""
+ pass
+
+
+cli.add_command(data)
+cli.add_command(trade)
+cli.add_command(backtest)
+cli.add_command(portfolio)
+cli.add_command(strategy)
+cli.add_command(service)
diff --git a/cli/tests/__init__.py b/cli/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cli/tests/__init__.py
diff --git a/cli/tests/test_cli_data.py b/cli/tests/test_cli_data.py
new file mode 100644
index 0000000..2cc2149
--- /dev/null
+++ b/cli/tests/test_cli_data.py
@@ -0,0 +1,17 @@
+from click.testing import CliRunner
+from trading_cli.main import cli
+
+
+def test_cli_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["--help"])
+ assert result.exit_code == 0
+ assert "Usage" in result.output
+
+
+def test_cli_data_group():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["data", "--help"])
+ assert result.exit_code == 0
+ assert "collect" in result.output
+ assert "history" in result.output
diff --git a/cli/tests/test_cli_trade.py b/cli/tests/test_cli_trade.py
new file mode 100644
index 0000000..d3f3079
--- /dev/null
+++ b/cli/tests/test_cli_trade.py
@@ -0,0 +1,10 @@
+from click.testing import CliRunner
+from trading_cli.main import cli
+
+
+def test_cli_trade_group():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["trade", "--help"])
+ assert result.exit_code == 0
+ assert "start" in result.output
+ assert "stop" in result.output