kitecli 0.3.1__tar.gz → 0.4.0__tar.gz

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 (40) hide show
  1. {kitecli-0.3.1 → kitecli-0.4.0}/PKG-INFO +1 -1
  2. {kitecli-0.3.1 → kitecli-0.4.0}/cli/api_client.py +82 -0
  3. {kitecli-0.3.1 → kitecli-0.4.0}/cli/base_manager.py +8 -0
  4. {kitecli-0.3.1 → kitecli-0.4.0}/cli/charges.py +3 -3
  5. kitecli-0.4.0/cli/display.py +773 -0
  6. {kitecli-0.3.1 → kitecli-0.4.0}/cli/executor.py +96 -1
  7. kitecli-0.4.0/cli/greeks.py +334 -0
  8. {kitecli-0.3.1 → kitecli-0.4.0}/cli/indicators.py +6 -3
  9. {kitecli-0.3.1 → kitecli-0.4.0}/cli/kite_manager.py +186 -0
  10. {kitecli-0.3.1 → kitecli-0.4.0}/cli/kotak_manager.py +131 -0
  11. {kitecli-0.3.1 → kitecli-0.4.0}/cli/live_session.py +1837 -159
  12. {kitecli-0.3.1 → kitecli-0.4.0}/cli/main.py +60 -0
  13. {kitecli-0.3.1 → kitecli-0.4.0}/cli/nli.py +1 -1
  14. kitecli-0.4.0/cli/parser.py +511 -0
  15. {kitecli-0.3.1 → kitecli-0.4.0}/cli/recorder.py +449 -7
  16. {kitecli-0.3.1 → kitecli-0.4.0}/kitecli.egg-info/PKG-INFO +1 -1
  17. {kitecli-0.3.1 → kitecli-0.4.0}/kitecli.egg-info/SOURCES.txt +3 -0
  18. {kitecli-0.3.1 → kitecli-0.4.0}/pyproject.toml +1 -1
  19. kitecli-0.4.0/tests/test_command_matrix.py +401 -0
  20. kitecli-0.4.0/tests/test_conditional_orders.py +515 -0
  21. {kitecli-0.3.1 → kitecli-0.4.0}/tests/test_multi_broker.py +126 -0
  22. {kitecli-0.3.1 → kitecli-0.4.0}/tests/test_parser.py +121 -0
  23. kitecli-0.4.0/tests/test_scheduled_orders.py +394 -0
  24. kitecli-0.4.0/tests/test_ui.py +397 -0
  25. kitecli-0.3.1/cli/display.py +0 -389
  26. kitecli-0.3.1/cli/greeks.py +0 -160
  27. kitecli-0.3.1/cli/parser.py +0 -181
  28. kitecli-0.3.1/tests/test_ui.py +0 -153
  29. {kitecli-0.3.1 → kitecli-0.4.0}/README.md +0 -0
  30. {kitecli-0.3.1 → kitecli-0.4.0}/cli/__init__.py +0 -0
  31. {kitecli-0.3.1 → kitecli-0.4.0}/cli/advisor.py +0 -0
  32. {kitecli-0.3.1 → kitecli-0.4.0}/cli/config.py +0 -0
  33. {kitecli-0.3.1 → kitecli-0.4.0}/cli/telegram_bot.py +0 -0
  34. {kitecli-0.3.1 → kitecli-0.4.0}/kitecli.egg-info/dependency_links.txt +0 -0
  35. {kitecli-0.3.1 → kitecli-0.4.0}/kitecli.egg-info/entry_points.txt +0 -0
  36. {kitecli-0.3.1 → kitecli-0.4.0}/kitecli.egg-info/requires.txt +0 -0
  37. {kitecli-0.3.1 → kitecli-0.4.0}/kitecli.egg-info/top_level.txt +0 -0
  38. {kitecli-0.3.1 → kitecli-0.4.0}/setup.cfg +0 -0
  39. {kitecli-0.3.1 → kitecli-0.4.0}/tests/test_nli.py +0 -0
  40. {kitecli-0.3.1 → kitecli-0.4.0}/tests/test_telegram.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kitecli
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: KiteCLI — Multi-account, multi-broker trading positions viewer (Zerodha + Kotak Neo)
5
5
  Author: KiteCLI Team
6
6
  License: MIT
@@ -537,6 +537,73 @@ class KCLIClient:
537
537
 
538
538
  return {"accounts": results}
539
539
 
540
+ def get_holdings(self, api_keys: list[str] | None = None) -> dict:
541
+ """Fetch stock/equity holdings for specified accounts in parallel."""
542
+ keys = api_keys or [a.get("api_key") for a in self._accounts if a.get("api_key")]
543
+
544
+ def fetch_one(api_key):
545
+ mgr = _manager_for(api_key)
546
+ info = mgr.get_account_info(api_key)
547
+ broker = getattr(mgr, "broker_name", "zerodha")
548
+ if not info.get("authenticated"):
549
+ return {
550
+ "name": info.get("name", api_key),
551
+ "api_key": api_key,
552
+ "broker": broker,
553
+ "holdings": [],
554
+ "total_investment": 0.0,
555
+ "total_current_value": 0.0,
556
+ "total_pnl": 0.0,
557
+ "total_day_change": 0.0,
558
+ "status": "unauthenticated",
559
+ }
560
+ try:
561
+ holdings = mgr.get_holdings(api_key)
562
+ tot_inv = sum(h.get("investment_value", 0.0) for h in holdings)
563
+ tot_cur = sum(h.get("current_value", 0.0) for h in holdings)
564
+ tot_pnl = tot_cur - tot_inv
565
+ tot_day = sum(h.get("day_change", 0.0) for h in holdings)
566
+ return {
567
+ "name": info.get("name", api_key),
568
+ "api_key": api_key,
569
+ "broker": broker,
570
+ "holdings": holdings,
571
+ "total_investment": tot_inv,
572
+ "total_current_value": tot_cur,
573
+ "total_pnl": tot_pnl,
574
+ "total_day_change": tot_day,
575
+ "status": "success",
576
+ }
577
+ except Exception as exc:
578
+ return {
579
+ "name": info.get("name", api_key),
580
+ "api_key": api_key,
581
+ "broker": broker,
582
+ "holdings": [],
583
+ "total_investment": 0.0,
584
+ "total_current_value": 0.0,
585
+ "total_pnl": 0.0,
586
+ "total_day_change": 0.0,
587
+ "status": f"error: {exc}",
588
+ }
589
+
590
+ with ThreadPoolExecutor(max_workers=max(1, len(keys))) as executor:
591
+ results = list(executor.map(fetch_one, keys))
592
+
593
+ grand_inv = sum(a.get("total_investment", 0.0) for a in results)
594
+ grand_cur = sum(a.get("total_current_value", 0.0) for a in results)
595
+ grand_pnl = grand_cur - grand_inv
596
+ grand_day = sum(a.get("total_day_change", 0.0) for a in results)
597
+
598
+ return {
599
+ "accounts": results,
600
+ "grand_total_investment": grand_inv,
601
+ "grand_total_current_value": grand_cur,
602
+ "grand_total_pnl": grand_pnl,
603
+ "grand_total_day_change": grand_day,
604
+ "status": "success",
605
+ }
606
+
540
607
  def modify_order(
541
608
  self,
542
609
  api_key: str,
@@ -636,3 +703,18 @@ class KCLIClient:
636
703
  return mgr.get_ltp_and_tokens(api_key, symbols)
637
704
  return {}
638
705
 
706
+ def get_market_depth(self, symbol: str) -> dict:
707
+ """Fetch 5-depth order book, OHLC, and market stats for a symbol."""
708
+ if hasattr(_kite_manager, "get_market_depth"):
709
+ res = _kite_manager.get_market_depth(symbol)
710
+ if res.get("status") == "success":
711
+ return res
712
+
713
+ for mgr in [_kotak_manager]:
714
+ if hasattr(mgr, "get_market_depth"):
715
+ res = mgr.get_market_depth(symbol)
716
+ if res.get("status") == "success":
717
+ return res
718
+
719
+ return {"status": "error", "message": f"Market depth not available for symbol '{symbol}'"}
720
+
@@ -81,6 +81,10 @@ class BaseBrokerManager(ABC):
81
81
  def get_margins(self, account_key: str) -> dict[str, Any]:
82
82
  """Return {"net": float|None, "cash": float|None, "collateral": float|None}."""
83
83
 
84
+ @abstractmethod
85
+ def get_holdings(self, account_key: str) -> list[dict[str, Any]]:
86
+ """Fetch equity/stock holdings using the normalised schema."""
87
+
84
88
  # ── order management ──────────────────────────────────────────────────────
85
89
 
86
90
  @abstractmethod
@@ -157,3 +161,7 @@ class BaseBrokerManager(ABC):
157
161
  ) -> dict[str, Any]:
158
162
  """Calculate margin required for a proposed order. Default: fallback estimation."""
159
163
  return {"status": "error", "message": "not supported by this broker"}
164
+
165
+ def get_market_depth(self, symbol: str) -> dict[str, Any]:
166
+ """Fetch 5-depth order book, OHLC, and market stats for a symbol. Default: not supported."""
167
+ return {"status": "error", "message": "not supported by this broker"}
@@ -7,7 +7,7 @@ Official Rates from https://zerodha.com/charges/#charges-explained:
7
7
  - GST: 18% on (brokerage + SEBI charges + transaction charges).
8
8
  - SEBI charges: ₹10 / crore (0.0001%).
9
9
  - Stamp charges: 0.003% or ₹300 / crore on buy side.
10
- - IPFT fee: ₹50 / crore (0.0005%).
10
+ - IPFT fee: ₹0.01 / crore (0.0000001%).
11
11
  """
12
12
 
13
13
  from typing import Any
@@ -55,8 +55,8 @@ def calculate_option_charges(
55
55
  # 4. SEBI turnover fee: ₹10 / crore (0.0001%)
56
56
  sebi_fee = round(total_val * 0.000001, 2)
57
57
 
58
- # 5. IPFT fee: ₹50 / crore (0.000005%) for NSE/NFO
59
- ipft_fee = round(total_val * 0.000005, 2) if is_nse else 0.0
58
+ # 5. IPFT fee: ₹0.01 / crore (0.0000001%) for NSE/NFO
59
+ ipft_fee = round(total_val * 1e-9, 2) if is_nse else 0.0
60
60
 
61
61
  # 6. GST: 18% on (Brokerage + Exchange Fee + SEBI Fee)
62
62
  gst = round((brokerage + exch_fee + sebi_fee) * 0.18, 2)