@drico2008/fincli 0.1.2 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +81 -7
  2. package/fincli/__init__.py +1 -1
  3. package/fincli/app/analysis/assistant_context.py +27 -1
  4. package/fincli/app/analysis/indicators.py +1 -1
  5. package/fincli/app/analysis/market_structure.py +1 -1
  6. package/fincli/app/cli/commands.py +12 -4
  7. package/fincli/app/cli/router.py +253 -13
  8. package/fincli/app/modules/session_history.py +113 -0
  9. package/fincli/app/providers/ai/anthropic_provider.py +8 -7
  10. package/fincli/app/providers/ai/gemini_provider.py +8 -7
  11. package/fincli/app/providers/ai/groq_provider.py +8 -7
  12. package/fincli/app/providers/ai/http_provider.py +3 -3
  13. package/fincli/app/providers/ai/huggingface_provider.py +8 -7
  14. package/fincli/app/providers/ai/openai_provider.py +8 -7
  15. package/fincli/app/providers/ai/openrouter_provider.py +8 -7
  16. package/fincli/app/providers/ai/together_provider.py +8 -7
  17. package/fincli/app/providers/market/custom_provider.py +2 -2
  18. package/fincli/app/providers/market/finnhub_provider.py +1 -1
  19. package/fincli/app/providers/market/manager.py +6 -5
  20. package/fincli/app/providers/market/news_provider.py +4 -4
  21. package/fincli/app/providers/market/twelvedata_provider.py +1 -1
  22. package/fincli/app/providers/market/yfinance_provider.py +1 -1
  23. package/fincli/app/services/web_research.py +267 -0
  24. package/fincli/app/storage/cache.py +2 -2
  25. package/fincli/app/storage/config.py +3 -4
  26. package/fincli/app/storage/config_paths.py +9 -0
  27. package/fincli/app/storage/database.py +17 -0
  28. package/fincli/app/storage/secrets.py +104 -0
  29. package/fincli/app/tui/components.py +1 -1
  30. package/fincli/app/tui/layout.py +8 -7
  31. package/fincli/app/tui/market_provider_selector.py +42 -2
  32. package/fincli/app/tui/model_selector.py +97 -55
  33. package/fincli/app/utils/formatting.py +50 -0
  34. package/npm/bin/fincli.js +9 -2
  35. package/package.json +1 -1
  36. package/pyproject.toml +1 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  FinCLI adalah financial CLI/TUI terminal modern untuk memantau market, mengelola watchlist, portfolio, journal, konfigurasi provider, dan menyiapkan integrasi AI market analysis secara modular.
4
4
 
5
- Status saat ini: Phase 23 MVP sudah aktif di atas fondasi Phase 1 sampai Phase 22.
5
+ Status saat ini: FinCLI MVP aktif dengan TUI, provider chain, AI assistance, web research, portfolio, journal, watchlist, export, dan session history lokal.
6
6
 
7
7
  - Textual TUI satu kolom dengan command palette inline yang bisa discroll; sidebar lama sudah dihapus agar output market lebih lega.
8
8
  - Slash command router dengan command wajib FinCLI v0.1.
@@ -90,6 +90,24 @@ copy .env.example .env
90
90
 
91
91
  Isi API key hanya untuk provider yang ingin digunakan. yfinance fallback tidak butuh API key. Config membaca status key tanpa menampilkan secret.
92
92
 
93
+ Untuk install global lewat npm, user tidak perlu membuka folder package atau mengedit `.env`. Simpan API key lewat command FinCLI:
94
+
95
+ ```text
96
+ /ai_model key groq <api_key>
97
+ /ai_model key openrouter <api_key>
98
+ /news_model key finnhub <api_key>
99
+ /news_model key twelvedata <api_key>
100
+ /news_model key custom <api_key> https://your-market-api.example.com
101
+ ```
102
+
103
+ Key disimpan lokal di:
104
+
105
+ ```text
106
+ ~/.fincli/secrets.env
107
+ ```
108
+
109
+ File ini tidak dicetak penuh di output terminal. `/config` dan `/provider key status` hanya menampilkan status/masked key.
110
+
93
111
  ## Run
94
112
 
95
113
  ```bash
@@ -130,12 +148,17 @@ python -m fincli.app.main
130
148
  /journal add BTC-USD bullish "Breakout gagal, tunggu konfirmasi"
131
149
  /journal stats
132
150
  /journal review
133
- /price AAPL
151
+ /history
152
+ /history sessions
153
+ /history save "Riset market pagi"
154
+ /quote AAPL
134
155
  /technical BTC-USD 1d
135
156
  /technical XAUUSD 1d
136
157
  /technical EURUSD 1d
137
158
  /structure BTC-USD 1d
138
159
  /news AAPL
160
+ /web penyebab rupiah melemah hari ini
161
+ /web sources penyebab rupiah melemah hari ini
139
162
  /funda MSFT
140
163
  /yahoo BBRI history 6mo 1d
141
164
  /yahoo BBRI statistics
@@ -159,7 +182,7 @@ python -m fincli.app.main
159
182
  /exit
160
183
  ```
161
184
 
162
- Command `/market`, `/price`, `/quote`, `/technical`, `/structure`, `/news`, dan `/funda` sudah memakai provider chain aktif. Command `/ai` dan `/analyze` sudah memakai AI provider aktif dari `/ai_model` dan `.env`. `/analyze` membawa konteks indikator, struktur pasar, news, dan fundamental ringkas ke prompt AI. `/ai` juga mengambil quote, OHLCV/technical, structure, news, dan fundamental saat user menyebut symbol seperti `AAPL`, `EURUSD`, atau `XAUUSD`.
185
+ Command `/market`, `/quote`, `/technical`, `/structure`, `/news`, dan `/funda` sudah memakai provider chain aktif. Command `/ai` dan `/analyze` sudah memakai AI provider aktif dari `/ai_model` dan `.env`. `/analyze` membawa konteks indikator, struktur pasar, news, dan fundamental ringkas ke prompt AI. `/ai` juga mengambil quote, OHLCV/technical, structure, news, dan fundamental saat user menyebut symbol seperti `AAPL`, `EURUSD`, atau `XAUUSD`.
163
186
 
164
187
  ## AI Chat UX
165
188
 
@@ -189,8 +212,31 @@ AI assistant di dalam FinCLI dipersonalisasi untuk market workflow:
189
212
  - Boleh free chat untuk pertanyaan umum, market, portfolio, journal, provider, dan risk workflow.
190
213
  - Menolak coding/debugging/refactor/pembuatan software di dalam assistant FinCLI agar fokus app tetap jelas.
191
214
  - Jika prompt berisi symbol eksplisit, FinCLI menyisipkan market context dari provider chain aktif sebelum memanggil AI provider.
215
+ - Jika prompt membutuhkan info terkini, FinCLI dapat mengambil konteks web publik dan memasukkannya ke AI prompt.
192
216
  - Tidak membocorkan API key dan tidak mengklaim realtime jika provider aktif hanya delayed/fallback.
193
217
 
218
+ Contoh web-aware freechat:
219
+
220
+ ```text
221
+ apa yang menyebabkan penurunan rupiah terhadap semua mata uang hari ini
222
+ berita terbaru BI rate dan dampaknya ke IHSG
223
+ ```
224
+
225
+ Untuk web search yang dirangkum oleh AI:
226
+
227
+ ```text
228
+ /web penyebab rupiah melemah hari ini
229
+ /web update harga emas dan dollar index
230
+ ```
231
+
232
+ Untuk melihat sumber mentah tanpa ringkasan AI:
233
+
234
+ ```text
235
+ /web sources penyebab rupiah melemah hari ini
236
+ ```
237
+
238
+ FinCLI memakai lightweight HTTP web research, bukan Chrome automation. Ini lebih stabil untuk npm global install dan tidak membuka browser di background. Output tetap harus diverifikasi karena kualitas sumber web bisa berbeda-beda.
239
+
194
240
  ## Interactive AI Model Selector
195
241
 
196
242
  ```text
@@ -202,6 +248,7 @@ Di TUI, command ini membuka selector seperti modern CLI:
202
248
  - Select Provider
203
249
  - Status provider current/configured
204
250
  - Use existing configuration / configure again
251
+ - Configure API key jika provider belum punya key
205
252
  - Select Model
206
253
  - Search model/provider
207
254
  - Navigasi `up/down`, `Enter`, `Tab`, dan `Esc`
@@ -222,6 +269,7 @@ Di TUI, command ini membuka selector untuk provider market/news dan fallback pri
222
269
 
223
270
  - Select Market/News Provider
224
271
  - Pilih `Twelve Data`, `Finnhub`, `Custom API`, atau `Yahoo Finance`
272
+ - Masukkan API key langsung dari popup jika provider belum dikonfigurasi
225
273
  - Pilih preset fallback: recommended, primary + yfinance, data API priority, atau yfinance only
226
274
  - Search provider/preset
227
275
  - Navigasi `up/down`, `Enter`, `Tab`, dan `Esc`
@@ -436,6 +484,7 @@ Contoh:
436
484
 
437
485
  ```bash
438
486
  /ai_model openrouter openai/gpt-4o-mini
487
+ /ai_model key openrouter <api_key>
439
488
  /ai jelaskan risiko market NVDA secara singkat
440
489
  /analyze AAPL 1d
441
490
  ```
@@ -453,7 +502,7 @@ FinCLI memakai yfinance untuk akses saham global yang tersedia di Yahoo Finance.
453
502
  Command:
454
503
 
455
504
  ```text
456
- /price BBRI
505
+ /quote BBRI
457
506
  /technical BBRI 1d
458
507
  /analyze BBRI 1d
459
508
  /yahoo BBRI history 6mo 1d
@@ -496,6 +545,12 @@ Environment variable:
496
545
  FINNHUB_API_KEY=your-finnhub-key
497
546
  ```
498
547
 
548
+ Atau simpan dari FinCLI:
549
+
550
+ ```text
551
+ /news_model key finnhub <api_key>
552
+ ```
553
+
499
554
  Endpoint Finnhub yang dipakai:
500
555
 
501
556
  ```text
@@ -524,6 +579,12 @@ Environment variable:
524
579
  TWELVE_DATA_API_KEY=your-twelve-data-key
525
580
  ```
526
581
 
582
+ Atau simpan dari FinCLI:
583
+
584
+ ```text
585
+ /news_model key twelvedata <api_key>
586
+ ```
587
+
527
588
  Endpoint Twelve Data yang dipakai:
528
589
 
529
590
  ```text
@@ -571,6 +632,12 @@ MARKET_DATA_API_KEY=your-key
571
632
  MARKET_DATA_BASE_URL=https://your-market-api.example.com
572
633
  ```
573
634
 
635
+ Atau simpan dari FinCLI:
636
+
637
+ ```text
638
+ /news_model key custom <api_key> https://your-market-api.example.com
639
+ ```
640
+
574
641
  FinCLI akan memanggil endpoint:
575
642
 
576
643
  ```text
@@ -604,7 +671,14 @@ FinCLI menyimpan data lokal di:
604
671
  ~/.fincli/fincli.log
605
672
  ```
606
673
 
607
- API key tidak disimpan di output terminal dan sebaiknya tetap berada di `.env` atau environment variable.
674
+ API key tidak disimpan di output terminal. Untuk install global via npm, jalur utama adalah command FinCLI:
675
+
676
+ ```text
677
+ /ai_model key groq <api_key>
678
+ /news_model key twelvedata <api_key>
679
+ ```
680
+
681
+ Key disimpan lokal di `~/.fincli/secrets.env`, dipakai otomatis untuk semua session FinCLI berikutnya, dan tidak perlu dikonfigurasi ulang. Jika `.env` lokal berisi nilai kosong, FinCLI tetap memakai secret lokal yang sudah tersimpan.
608
682
 
609
683
  ## Test
610
684
 
@@ -622,8 +696,8 @@ Hasil terakhir di environment ini:
622
696
 
623
697
  - `fincli` tidak dikenali: jalankan `pip install -e .` dari root project.
624
698
  - TUI tidak tampil rapi: perbesar terminal desktop.
625
- - API key tidak terbaca: pastikan file `.env` ada di root project atau export environment variable.
626
- - `/price` gagal karena yfinance belum ada: jalankan `pip install -e ".[dev]"` atau `pip install -r requirements.txt`.
699
+ - API key tidak terbaca: gunakan `/ai_model key <provider> <api_key>` atau `/news_model key <provider> <api_key>`, lalu cek `/config` atau `/provider key status`.
700
+ - `/quote` gagal karena yfinance belum ada: jalankan `pip install -e ".[dev]"` atau `pip install -r requirements.txt`.
627
701
  - Config rusak: hapus `~/.fincli/config.json` untuk kembali ke default.
628
702
 
629
703
  ## Roadmap Lanjutan
@@ -1,3 +1,3 @@
1
1
  """FinCLI package."""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.9"
@@ -15,6 +15,7 @@ Identity and scope:
15
15
 
16
16
  Financial analysis rules:
17
17
  - Analyze from provided market context first. Do not invent prices, news, fundamentals, provider status, or certainty.
18
+ - If Web Research Context is provided, use it as current public context, mention source URLs, and separate sourced facts from interpretation.
18
19
  - Use probabilistic language: scenario, bias, confirmation, invalidation, risk, caution.
19
20
  - Do not promise profit and do not present aggressive entries as guaranteed signals.
20
21
  - For technical analysis, weigh trend, momentum, volatility, support/resistance, market structure, and data quality.
@@ -155,7 +156,32 @@ def build_fincli_assistant_prompt(user_prompt: str, market_context: str = "") ->
155
156
  f"{user_prompt.strip()}\n\n"
156
157
  "Instruction:\n"
157
158
  "- Answer the user's prompt directly.\n"
158
- "- If market context is present, cite provider/data-quality limitations.\n"
159
+ "- If market or web context is present, cite provider/data-quality limitations and source URLs when available.\n"
159
160
  "- If market context is missing and the user asks about an instrument, say what data is missing.\n"
160
161
  "- Keep the coding boundary enforced.\n"
161
162
  )
163
+
164
+
165
+ def build_web_research_answer_prompt(user_prompt: str, web_context: str) -> str:
166
+ """Build a prompt that turns gathered web context into an answer, not a source dump."""
167
+ context = web_context.strip() or "Web Research: no public web context returned."
168
+ return (
169
+ f"{FINCLI_ASSISTANT_SYSTEM_PROMPT}\n\n"
170
+ "Web Search Skill Result:\n"
171
+ f"{context}\n\n"
172
+ "User Prompt:\n"
173
+ f"{user_prompt.strip()}\n\n"
174
+ "Instruction:\n"
175
+ "- You already have web search context above. Do not answer by only listing articles or links.\n"
176
+ "- Synthesize the sources into a useful explanation/summary for the user.\n"
177
+ "- Prioritize facts found in the web context, then clearly label interpretation.\n"
178
+ "- If sources disagree or are thin, say that the evidence is limited.\n"
179
+ "- Use this output structure when relevant:\n"
180
+ " 1. Ringkasan singkat\n"
181
+ " 2. Poin utama/penyebab\n"
182
+ " 3. Dampak atau implikasi\n"
183
+ " 4. Risiko dan hal yang perlu diverifikasi\n"
184
+ " 5. Sumber singkat\n"
185
+ "- Keep source citations compact: source title or URL only where useful.\n"
186
+ "- Do not provide financial advice or certainty about market direction.\n"
187
+ )
@@ -26,7 +26,7 @@ class TechnicalSummary:
26
26
 
27
27
 
28
28
  def phase_one_indicator_status() -> str:
29
- return "Indicator engine scaffold ready. pandas/numpy/yfinance integration planned for Phase 2."
29
+ return "Indicator engine active: SMA, EMA, RSI, MACD, Bollinger Bands, ATR, volume, support, and resistance."
30
30
 
31
31
 
32
32
  def summarize_technical_indicators(candles: list[Candle]) -> TechnicalSummary:
@@ -20,7 +20,7 @@ class MarketStructureSummary:
20
20
 
21
21
 
22
22
  def phase_one_structure_status() -> str:
23
- return "Market structure scaffold ready. HH/HL/LH/LL detection planned for Phase 2."
23
+ return "Market structure engine active: HH/HL/LH/LL, BOS, CHoCH, liquidity area, and risk zone."
24
24
 
25
25
 
26
26
  def analyze_market_structure(candles: list[Candle], lookback: int = 20) -> MarketStructureSummary:
@@ -17,9 +17,13 @@ COMMANDS: tuple[CommandSpec, ...] = (
17
17
  CommandSpec("/help", "Tampilkan bantuan, command list, dan contoh.", "/help"),
18
18
  CommandSpec("/dashboard", "Tampilkan dashboard compact FinCLI.", "/dashboard", "General"),
19
19
  CommandSpec("/ai_model", "Lihat atau ganti AI provider/model.", "/ai_model openrouter openai/gpt-4o-mini", "AI"),
20
+ CommandSpec("/ai_model key", "Simpan API key AI lokal.", "/ai_model key groq <api_key>", "AI"),
20
21
  CommandSpec("/news_model", "Buka selector provider market/news dan fallback.", "/news_model", "Provider"),
22
+ CommandSpec("/news_model key", "Simpan API key market/news lokal.", "/news_model key finnhub <api_key>", "Provider"),
21
23
  CommandSpec("/market", "Ringkasan market profesional untuk instrumen.", "/market AAPL 1d", "Market"),
22
24
  CommandSpec("/news", "Tampilkan news/fundamental terbaru untuk instrumen.", "/news AAPL", "Market"),
25
+ CommandSpec("/web", "Web search lalu AI merangkum jawaban.", "/web penyebab rupiah melemah hari ini", "Research"),
26
+ CommandSpec("/web sources", "Tampilkan sumber mentah hasil web search.", "/web sources penyebab rupiah melemah hari ini", "Research"),
23
27
  CommandSpec("/technical", "Analisis teknikal instrumen.", "/technical BTC-USD 1d", "Analysis"),
24
28
  CommandSpec("/structure", "Analisis struktur pasar instrumen.", "/structure BTC-USD 1d", "Analysis"),
25
29
  CommandSpec("/funda", "Fundamental ringkas instrumen.", "/funda MSFT", "Market"),
@@ -39,9 +43,13 @@ COMMANDS: tuple[CommandSpec, ...] = (
39
43
  CommandSpec("/journal add", "Tambahkan catatan journal singkat.", '/journal add BTC-USD bullish "Breakout gagal, tunggu konfirmasi"', "Journal"),
40
44
  CommandSpec("/journal stats", "Tampilkan statistik journal.", "/journal stats", "Journal"),
41
45
  CommandSpec("/journal review", "AI review kebiasaan journal.", "/journal review", "Journal"),
46
+ CommandSpec("/history", "Tampilkan command history current session.", "/history", "History"),
47
+ CommandSpec("/history sessions", "Tampilkan daftar session tersimpan.", "/history sessions", "History"),
48
+ CommandSpec("/history show", "Tampilkan detail session tertentu.", "/history show <session_id>", "History"),
49
+ CommandSpec("/history save", "Beri nama current session.", '/history save "Riset IHSG pagi"', "History"),
50
+ CommandSpec("/history delete", "Hapus session tertentu.", "/history delete <session_id>", "History"),
42
51
  CommandSpec("/config", "Tampilkan konfigurasi aktif tanpa membocorkan API key.", "/config"),
43
- CommandSpec("/price", "Tampilkan harga instrumen.", "/price NVDA", "Market"),
44
- CommandSpec("/quote", "Alias harga/quote instrumen.", "/quote NVDA", "Market"),
52
+ CommandSpec("/quote", "Tampilkan harga/quote instrumen.", "/quote NVDA", "Market"),
45
53
  CommandSpec("/scan", "Scanner watchlist dengan filter indikator.", "/scan watchlist rsi<30", "Market"),
46
54
  CommandSpec("/calendar", "Economic calendar provider/fallback.", "/calendar week US high", "Market"),
47
55
  CommandSpec("/provider status", "Tampilkan status provider aktif.", "/provider status", "Provider"),
@@ -50,8 +58,8 @@ COMMANDS: tuple[CommandSpec, ...] = (
50
58
  CommandSpec("/provider key status", "Tampilkan status API key market provider.", "/provider key status", "Provider"),
51
59
  CommandSpec("/cache stats", "Tampilkan statistik cache market persistent.", "/cache stats", "System"),
52
60
  CommandSpec("/cache clear", "Bersihkan runtime dan persistent market cache.", "/cache clear", "System"),
53
- CommandSpec("/export journal", "Export journal. Phase 1 menyiapkan command.", "/export journal", "Export"),
54
- CommandSpec("/export portfolio", "Export portfolio. Phase 1 menyiapkan command.", "/export portfolio", "Export"),
61
+ CommandSpec("/export journal", "Export journal ke CSV/JSON.", "/export journal csv journal.csv", "Export"),
62
+ CommandSpec("/export portfolio", "Export portfolio ke CSV/JSON.", "/export portfolio json portfolio.json", "Export"),
55
63
  CommandSpec("/clear", "Bersihkan output terminal.", "/clear"),
56
64
  CommandSpec("/exit", "Keluar dari aplikasi.", "/exit"),
57
65
  )