mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-08-07 01:33:52 +00:00
feat(analysis): add technical analysis module and stocks technical command
- Add analysis module: SMA, EMA, RSI(14), MACD(12,26,9), volume ratio - Add signal interpretation: bullish/bearish/neutral with consensus voting - Wire up 'stocks technical <SYMBOL>' CLI subcommand - Table output with colored signals + JSON output support - Cache/offline/stale-cache fallback (same pattern as quote/history) - Fetch 1 year of daily data for SMA200 coverage (~250 trading days) - Add TechnicalReport, MacdSnapshot, VolumeSnapshot structs - Add 4 new unit tests + 3 integration tests (30 total passing)
This commit is contained in:
parent
9e0560f3c1
commit
9182f25a01
8 changed files with 723 additions and 6 deletions
52
tests/cli.rs
52
tests/cli.rs
|
|
@ -1,10 +1,10 @@
|
|||
use std::fs;
|
||||
|
||||
use assert_cmd::{Command, cargo::cargo_bin};
|
||||
use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
|
||||
fn bin() -> Command {
|
||||
Command::new(cargo_bin("idx-cli"))
|
||||
Command::new(assert_cmd::cargo::cargo_bin!("idx-cli"))
|
||||
}
|
||||
|
||||
fn test_env_dir(name: &str) -> std::path::PathBuf {
|
||||
|
|
@ -64,6 +64,30 @@ fn history_with_mock_provider_table_contains_columns() {
|
|||
.stdout(predicate::str::contains("VOLUME"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn technical_with_mock_provider_table_contains_expected_rows() {
|
||||
bin()
|
||||
.env("IDX_USE_MOCK_PROVIDER", "1")
|
||||
.args(["stocks", "technical", "BBCA"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Technical Analysis for"))
|
||||
.stdout(predicate::str::contains("RSI (14)"))
|
||||
.stdout(predicate::str::contains("Overall Signal"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn technical_with_mock_provider_json_contains_fields() {
|
||||
bin()
|
||||
.env("IDX_USE_MOCK_PROVIDER", "1")
|
||||
.args(["-o", "json", "stocks", "technical", "BBCA"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"symbol\""))
|
||||
.stdout(predicate::str::contains("\"sma20\""))
|
||||
.stdout(predicate::str::contains("\"signals\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_path_prints_path() {
|
||||
bin()
|
||||
|
|
@ -129,6 +153,30 @@ fn serves_stale_cache_on_provider_failure_with_warning() {
|
|||
.stderr(predicate::str::contains("warning: network failed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn technical_serves_stale_cache_on_provider_failure_with_warning() {
|
||||
let root = test_env_dir("technical-stale");
|
||||
let cache_home = root.join("cache");
|
||||
|
||||
bin()
|
||||
.env("XDG_CACHE_HOME", &cache_home)
|
||||
.env("IDX_USE_MOCK_PROVIDER", "1")
|
||||
.env("IDX_CACHE_QUOTE_TTL", "0")
|
||||
.args(["stocks", "technical", "BBCA"])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
bin()
|
||||
.env("XDG_CACHE_HOME", &cache_home)
|
||||
.env("IDX_USE_MOCK_PROVIDER", "1")
|
||||
.env("IDX_CACHE_QUOTE_TTL", "0")
|
||||
.env("IDX_MOCK_ERROR", "1")
|
||||
.args(["stocks", "technical", "BBCA"])
|
||||
.assert()
|
||||
.success()
|
||||
.stderr(predicate::str::contains("warning: network failed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_symbol_returns_non_zero() {
|
||||
bin()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue