sigma-terminal 3.4.0__py3-none-any.whl → 3.5.0__py3-none-any.whl

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.
@@ -0,0 +1,108 @@
1
+ from typing import Any, Callable, Dict, List, Optional
2
+ from pydantic import BaseModel
3
+ import inspect
4
+
5
+ class ToolDefinition(BaseModel):
6
+ name: str
7
+ description: str
8
+ input_schema: Dict[str, Any]
9
+ output_schema: Optional[Dict[str, Any]] = None
10
+ func: Callable
11
+ enabled: bool = True
12
+ provider: str = "internal" # yfinance, polygon, etc.
13
+
14
+ class ToolRegistry:
15
+ def __init__(self):
16
+ self._tools: Dict[str, ToolDefinition] = {}
17
+
18
+ def register(self, name: str, description: str, provider: str = "internal"):
19
+ def decorator(func):
20
+ # Extract schema from type hints (simplified)
21
+ # In a real impl, utilize pydantic.TypeAdapter or similar if args are models.
22
+ # Here we assume simple args or we use a manual schema if provided?
23
+ # For now, let's keep it simple: no schema auto-extraction in this snippet
24
+ # unless we implement a Schema generator.
25
+ # But the prompt says "typed tool registry... input_schema (pydantic)".
26
+
27
+ # minimal schema generation
28
+ sig = inspect.signature(func)
29
+ params = {}
30
+ required = []
31
+ for pname, p in sig.parameters.items():
32
+ if pname == "self": continue
33
+ p_type = "string"
34
+ if p.annotation == int: p_type = "integer"
35
+ if p.annotation == float: p_type = "number"
36
+ if p.annotation == bool: p_type = "boolean"
37
+
38
+ params[pname] = {"type": p_type}
39
+ if p.default == inspect.Parameter.empty:
40
+ required.append(pname)
41
+
42
+ schema = {
43
+ "type": "object",
44
+ "properties": params,
45
+ "required": required
46
+ }
47
+
48
+ self._tools[name] = ToolDefinition(
49
+ name=name,
50
+ description=description,
51
+ input_schema=schema,
52
+ func=func,
53
+ provider=provider
54
+ )
55
+ return func
56
+ return decorator
57
+
58
+ def get_tool(self, name: str) -> Optional[ToolDefinition]:
59
+ return self._tools.get(name)
60
+
61
+ def list_tools(self) -> List[ToolDefinition]:
62
+ return [t for t in self._tools.values() if t.enabled]
63
+
64
+ def to_llm_format(self) -> List[Dict[str, Any]]:
65
+ tools_list = []
66
+ for t in self.list_tools():
67
+ # Clone schema to avoid mutating original
68
+ import copy
69
+ schema = copy.deepcopy(t.input_schema)
70
+
71
+ # Inject thought parameter for Gemini/HackClub compatibility
72
+ # Some providers like Gemini via proxies require a "thought" field in tool calls
73
+ if "properties" in schema:
74
+ schema["properties"]["thought_signature"] = {
75
+ "type": "string",
76
+ "description": "Internal reasoning for why this tool is being called. MUST be provided."
77
+ }
78
+ # Force model to use it
79
+ if "required" in schema and isinstance(schema["required"], list):
80
+ schema["required"].append("thought_signature")
81
+ else:
82
+ schema["required"] = ["thought_signature"]
83
+
84
+ tools_list.append({
85
+ "type": "function",
86
+ "function": {
87
+ "name": t.name,
88
+ "description": t.description,
89
+ "parameters": schema
90
+ }
91
+ })
92
+ return tools_list
93
+
94
+ async def execute(self, name: str, args: Dict[str, Any]) -> Any:
95
+ tool = self.get_tool(name)
96
+ if not tool:
97
+ raise ValueError(f"Tool {name} not found")
98
+
99
+ # Remove provider-specific fields if present
100
+ args.pop("thought", None)
101
+ args.pop("thought_signature", None)
102
+
103
+ if inspect.iscoroutinefunction(tool.func):
104
+ return await tool.func(**args)
105
+ else:
106
+ return tool.func(**args)
107
+
108
+ TOOL_REGISTRY = ToolRegistry()
@@ -0,0 +1,83 @@
1
+ import re
2
+ from datetime import datetime, timedelta
3
+ from typing import List, Optional, Tuple
4
+
5
+ COMMON_TICKERS = {
6
+ # Ticker map for normalization if needed
7
+ "APPLE": "AAPL",
8
+ "GOOGLE": "GOOGL",
9
+ "MICROSOFT": "MSFT",
10
+ "AMAZON": "AMZN",
11
+ "TESLA": "TSLA",
12
+ "NVIDIA": "NVDA",
13
+ "META": "META",
14
+ "FACEBOOK": "META",
15
+ "NETFLIX": "NFLX",
16
+ "S&P 500": "SPY",
17
+ "SP500": "SPY",
18
+ "S&P": "SPY",
19
+ "NASDAQ": "QQQ",
20
+ "DOW": "DIA",
21
+ "DOW JONES": "DIA",
22
+ "BITCOIN": "BTC-USD",
23
+ "ETHEREUM": "ETH-USD",
24
+ }
25
+
26
+ def extract_tickers(text: str) -> List[str]:
27
+ """Extract and normalize tickers from text."""
28
+ found = []
29
+
30
+ # Check known names first (case insensitive bounds)
31
+ upper_text = text.upper()
32
+ for name, ticker in COMMON_TICKERS.items():
33
+ # Simple word boundary check
34
+ if re.search(r'\b' + re.escape(name) + r'\b', upper_text):
35
+ found.append(ticker)
36
+
37
+ # Regex for standard tickers (capitals, 1-5 chars)
38
+ # Exclude common words like I, A, AM, PM, IS, AT, VS, OR, AND...
39
+ # Strict mode: must be uppercase in original text? The prompt implies natural language which might be mixed.
40
+ # But usually users type tickers in caps or "Apple".
41
+
42
+ # For simplicity, extract probable tickers
43
+ matches = re.findall(r'\b[A-Z]{2,5}\b', text)
44
+ stopwords = {"AND", "OR", "THE", "FOR", "GET", "SET", "NOT", "BUT", "BY", "OF", "AT", "IN", "ON", "TO", "FROM", "VS", "GDP", "CPI", "USD", "YTD", "CEO", "CFO", "SEC", "API", "LLM", "AI"}
45
+
46
+ for m in matches:
47
+ if m not in stopwords and m not in found:
48
+ found.append(m)
49
+
50
+ return list(set(found))
51
+
52
+ def extract_timeframe(text: str) -> Tuple[str, Optional[str], Optional[str]]:
53
+ """Extract timeframe description, start date, end date."""
54
+
55
+ today = datetime.now()
56
+
57
+ # "5y", "10 years", "start of 2020"
58
+
59
+ # Simple regex for periods
60
+ match_years = re.search(r'\b(\d+)\s*y(ears?)?\b', text)
61
+ if match_years:
62
+ years = int(match_years.group(1))
63
+ start_date = (today - timedelta(days=years*365)).strftime("%Y-%m-%d")
64
+ return f"{years}y", start_date, None
65
+
66
+ match_months = re.search(r'\b(\d+)\s*m(onths?)?\b', text)
67
+ if match_months:
68
+ months = int(match_months.group(1))
69
+ start_date = (today - timedelta(days=months*30)).strftime("%Y-%m-%d")
70
+ return f"{months}m", start_date, None
71
+
72
+ # "Since 2021"
73
+ match_since = re.search(r'\bsince\s+(\d{4})\b', text)
74
+ if match_since:
75
+ year = int(match_since.group(1))
76
+ return f"since {year}", f"{year}-01-01", None
77
+
78
+ # "YTD"
79
+ if "YTD" in text.upper():
80
+ start_date = f"{today.year}-01-01"
81
+ return "YTD", start_date, None
82
+
83
+ return "default", None, None
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: sigma-terminal
3
+ Version: 3.5.0
4
+ Summary: Sigma - Finance Research Agent
5
+ Project-URL: Homepage, https://github.com/desenyon/sigma
6
+ Project-URL: Documentation, https://github.com/desenyon/sigma/wiki
7
+ Project-URL: Repository, https://github.com/desenyon/sigma
8
+ Author: Sigma Team
9
+ License: Proprietary
10
+ License-File: LICENSE
11
+ Keywords: ai,analytics,backtesting,finance,investment,portfolio,quantitative,research,stocks,terminal,trading
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: Other/Proprietary License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Office/Business :: Financial :: Investment
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: aiohttp>=3.9.0
22
+ Requires-Dist: anthropic>=0.18.0
23
+ Requires-Dist: google-genai>=1.0.0
24
+ Requires-Dist: groq>=0.4.0
25
+ Requires-Dist: httpx>=0.26.0
26
+ Requires-Dist: kaleido>=0.2.1
27
+ Requires-Dist: numpy>=1.26.0
28
+ Requires-Dist: openai>=1.12.0
29
+ Requires-Dist: pandas>=2.2.0
30
+ Requires-Dist: pillow>=10.2.0
31
+ Requires-Dist: plotext>=5.2.8
32
+ Requires-Dist: plotly>=5.18.0
33
+ Requires-Dist: pydantic-settings>=2.1.0
34
+ Requires-Dist: pydantic>=2.6.0
35
+ Requires-Dist: pyobjc-framework-cocoa>=10.0; sys_platform == 'darwin'
36
+ Requires-Dist: python-dotenv>=1.0.0
37
+ Requires-Dist: requests>=2.31.0
38
+ Requires-Dist: rich>=13.7.0
39
+ Requires-Dist: scipy>=1.12.0
40
+ Requires-Dist: textual>=0.47.0
41
+ Requires-Dist: yfinance>=0.2.36
42
+ Provides-Extra: all
43
+ Requires-Dist: black>=24.0.0; extra == 'all'
44
+ Requires-Dist: lean>=1.0.0; extra == 'all'
45
+ Requires-Dist: mypy>=1.8.0; extra == 'all'
46
+ Requires-Dist: py2app>=0.28.0; extra == 'all'
47
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'all'
48
+ Requires-Dist: pytest>=8.0.0; extra == 'all'
49
+ Requires-Dist: ruff>=0.2.0; extra == 'all'
50
+ Provides-Extra: dev
51
+ Requires-Dist: black>=24.0.0; extra == 'dev'
52
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
53
+ Requires-Dist: py2app>=0.28.0; extra == 'dev'
54
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
55
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
56
+ Requires-Dist: ruff>=0.2.0; extra == 'dev'
57
+ Provides-Extra: lean
58
+ Requires-Dist: lean>=1.0.0; extra == 'lean'
59
+ Description-Content-Type: text/markdown
60
+
61
+ <h1 align="center">
62
+ <code>σ</code> SIGMA
63
+ </h1>
64
+
65
+ <p align="center">
66
+ <strong>The Terminal-Based Financial Research Agent</strong>
67
+ </p>
68
+
69
+ <p align="center">
70
+ <img src="https://img.shields.io/badge/version-3.5.0-blue.svg" alt="Version 3.5.0"/>
71
+ <img src="https://img.shields.io/badge/python-3.11+-green.svg" alt="Python 3.11+"/>
72
+ <img src="https://img.shields.io/badge/license-Proprietary-red.svg" alt="License"/>
73
+ <img src="https://img.shields.io/badge/UI-Textual-purple.svg" alt="UI Framework"/>
74
+ </p>
75
+
76
+ ---
77
+
78
+ ## What is Sigma?
79
+
80
+ Sigma is a financial analysis terminal powered by modern AI. It unifies natural language research, quantitative backtesting, and real-time market data into a single, high-performance CLI application.
81
+
82
+ Unlike generic chat tools, Sigma is built for finance:
83
+
84
+ - **Deterministic Tools**: Real APIs for quotes, financials, and news—no hallucinations.
85
+ - **Local & Cloud AI**: Route queries to OpenAI, Anthropic, Gemini, or run locally with Ollama.
86
+ - **Integrated Backtesting**: First-class support for LEAN engine to test strategies instantly.
87
+ - **Privacy First**: Your API keys and strategies stay on your machine.
88
+
89
+ ---
90
+
91
+ ## Installation
92
+
93
+ ### Prerequisites
94
+
95
+ - Python 3.11+
96
+ - [Optional] Docker (for LEAN) or LEAN CLI
97
+ - [Optional] Ollama (for local inference)
98
+
99
+ ### One-Command Setup
100
+
101
+ Sigma includes an intelligent **Setup Agent** that handles the heavy lifting.
102
+
103
+ ```bash
104
+ # Clone and install
105
+ pip install sigma-terminal
106
+
107
+ # Launch (triggers Setup Agent on first run)
108
+ python -m sigma
109
+ ```
110
+
111
+ The Setup Agent will:
112
+
113
+ 1. Detect your OS and Python environment.
114
+ 2. Install the LEAN backtesting engine (if missing).
115
+ 3. Install and configure Ollama (if missing).
116
+ 4. help you add API keys for data providers (Polygon, Alpha Vantage, etc.).
117
+
118
+ ---
119
+
120
+ ## Usage
121
+
122
+ Sigma is designed for natural language. Just type what you need.
123
+
124
+ ### Market Research
125
+
126
+ > "Analyze AAPL and compare it with MSFT for the last 5 years"
127
+ > "Get me the latest earnings report for NVDA and summarize risks"
128
+ > "Show me a chart of SPY vs QQQ YTD"
129
+
130
+ ### Quantitative Backtesting
131
+
132
+ > "Backtest a simple moving average crossover on BTC-USD from 2020"
133
+ > "Run a momentum strategy on TSLA, weekly rebalance"
134
+
135
+ ### Tool & System Control
136
+
137
+ > "Switch model to local llama3"
138
+ > "List all available tools"
139
+ > "/backtest AAPL -s sma_cross" (Shortcuts available)
140
+
141
+ ---
142
+
143
+ ## Architecture
144
+
145
+ Sigma v3.5.0 is built on a modular, event-driven architecture:
146
+
147
+ | Component | Description |
148
+ | -------------------------- | ----------------------------------------------------------------------------------------------------- |
149
+ | **Core Engine** | Orchestrates intent parsing, tool routing, and result synthesis. |
150
+ | **LLM Router** | Intelligent routing between OpenAI, Anthropic, Google, and Ollama. Handles rate limits and fallbacks. |
151
+ | **Tool Registry** | A typed system connecting the LLM to 30+ financial data functions. |
152
+ | **Backtest Service** | Wraps the LEAN engine to stream logs and results directly to the TUI. |
153
+ | **UI (Textual)** | A multi-pane terminal interface with real-time streaming, trace logs, and plotting. |
154
+
155
+ ---
156
+
157
+ ## Configuration
158
+
159
+ Configuration is stored in `~/.sigma/` and managed automatically. You can also edit it manually:
160
+
161
+ `~/.sigma/config.json`:
162
+
163
+ ```json
164
+ {
165
+ "default_model": "gpt-4o",
166
+ "ollama_url": "http://localhost:11434",
167
+ "data_providers": {
168
+ "polygon": "ENABLED",
169
+ "yfinance": "FALLBACK"
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Supported Providers
175
+
176
+ - **AI**: OpenAI, Anthropic (Claude), Google (Gemini), Ollama (Local)
177
+ - **Data**: Polygon.io, Alpha Vantage, Financial Modeling Prep, YFinance (Default)
178
+
179
+ ---
180
+
181
+ ## License
182
+
183
+ Proprietary / Closed Source.
184
+ Copyright (c) 2026 Sigma Team. All Rights Reserved.
@@ -0,0 +1,46 @@
1
+ sigma/__init__.py,sha256=dcYKxj4v5MyKiYVaZ4_P1mLHBN9xxJWzToBeTO6Y0To,3574
2
+ sigma/__main__.py,sha256=JR33oXObSRLsirM_8pvzTIUBr16QXS294WkQRIFI95g,114
3
+ sigma/app.py,sha256=waFgdUzD8s67ctM9tsmzUxatK4y7rGgqZ4xQwY47v30,14493
4
+ sigma/charts.py,sha256=FMQ6kkX0OE1SMD_fcb2z-YGwX9Lcbc2bRpWpqLMzPGo,12784
5
+ sigma/cli.py,sha256=GCSkeQ7g1puHrgpUl7ZkyuKIMpKEzLfVhVPg3UB9Bl8,16935
6
+ sigma/comparison.py,sha256=0q-zWGVVuI8EMz7KsLVG5isORC2zRUTFCrht2Qjt8zk,21725
7
+ sigma/config.py,sha256=Wq9NeUn1ImRC-ZPRVVUDlpq8NZzIkx46_uGvg390Cgo,17397
8
+ sigma/monitoring.py,sha256=7iC9DaTX8dFIygwAyEgpFQFpLPQrmLg6UW1bBeB_n7M,22672
9
+ sigma/portfolio.py,sha256=ySypECWntDfa4pRVrNgxRsNDyOCEEgTOCUhrQIiMgBY,24020
10
+ sigma/reporting.py,sha256=3qzuG-uITeO2z9ENOst4QcJSY2z8FyJs_eGQVe7JGM4,19157
11
+ sigma/robustness.py,sha256=rvy-LQx9b7IZRYTI1srnL_yrVWeNAwcUFra0YSD6ZrE,23502
12
+ sigma/setup_agent.py,sha256=W9HfaNQTLEDnDeUvzZnyzw1AQE9A67RJ-nYf_IBVEPU,7686
13
+ sigma/strategy.py,sha256=1IucLv3vcWyQgAsMhav6Q1qf-i3yk3obYEdaOkRA4Nw,28881
14
+ sigma/visualization.py,sha256=w5amseNd-sO8oCUpE_jnZFQD2xW-Twx6W6kk6xSb-ZA,24749
15
+ sigma/analytics/__init__.py,sha256=WkyZgfvDSxbXKox-VV7mvnBhMC7l7y8qAv4Tfy0lYcQ,23191
16
+ sigma/backtest/__init__.py,sha256=Wko8jkF76S_WZSpIIfFK_GDaFnLZvsnH7HAVJPB4Y_M,112
17
+ sigma/backtest/service.py,sha256=_UzEOnmMV8sntAt9gYgUnpvn853Ne8EudoJf1Z0Zshg,4448
18
+ sigma/backtest/simple_engine.py,sha256=7hImn0A4eO6gokWVLKERWqapN1N-T9ohc8Vof1XJo-0,13258
19
+ sigma/core/__init__.py,sha256=vpMwe22zgDRze9LuGumTNvyRS2rzaeAgNd9_4dkaFrk,136
20
+ sigma/core/command_router.py,sha256=sJ4TCdAV99jBn6X4gBQh03PAt0BgeCdlnizj3SvaMUk,3442
21
+ sigma/core/engine.py,sha256=u8Z8ecvrPzaqyijHDjI4rDfdTpNjbAhxqx-5ahR8-0A,17566
22
+ sigma/core/intent.py,sha256=w3VOUIH7fQ0nSrG2Ch9l9CVfSU7dp0wqz5FCSu3e3HQ,23519
23
+ sigma/core/models.py,sha256=IkpvIK28rvGsjqV9cvC3NhbdiHaRmNzEJUevJkpLGyA,15745
24
+ sigma/data/__init__.py,sha256=nqFtjuuTGhEO7bs-eVAzesKIf0w7U_38qgkGi5O53Ek,23896
25
+ sigma/data/models.py,sha256=Zoh4s90ihPPVpUw3Nh5SqInNzf7l-jB8_I1de1OUDNQ,3694
26
+ sigma/llm/__init__.py,sha256=_ntoRdQKScfMA8aClrcuM4PT5WxJtXAZMcmxSCmBrWI,109
27
+ sigma/llm/rate_limit.py,sha256=vDHhQg142Wd8LrPLn0vsmO6LBsiuao-NuvHX_zE0Kh4,1537
28
+ sigma/llm/registry.py,sha256=OXcqUaqEMkRQ7e9RaFXPyvstX9X36NH6rG1bBk1qOPU,2866
29
+ sigma/llm/router.py,sha256=GlYwVO2lqfivRcEE-x8zOeYCZzPssLS1UTKdyws4rko,4605
30
+ sigma/llm/providers/anthropic_provider.py,sha256=eLE-z4R_tqNGQetPqr9Nl-Vh5G4Te4CxpHnH5_8k9d0,7663
31
+ sigma/llm/providers/base.py,sha256=OFWaCbIxWgY6bMxN5qnxydS-vWgvyLFvUacIzGaiLGM,866
32
+ sigma/llm/providers/google_provider.py,sha256=xryjOItRLhSWcSITSSnc2OkdfNiL3Y-fh9Asiyxy6cY,8381
33
+ sigma/llm/providers/ollama_provider.py,sha256=yqpejtZLtTjddaS99vkcUFq_8vDVHKMeMWn83fvln9E,6607
34
+ sigma/llm/providers/openai_provider.py,sha256=UFfkGBMGVBA-Zcprc-0XrGNWxuFl0aTghYPprtbRDVY,6903
35
+ sigma/llm/providers/sigma_cloud_provider.py,sha256=mCT445D0LSwE7Th79QTT-6Y9QRzoSmZfXBmzADrSp9M,1838
36
+ sigma/tools/__init__.py,sha256=kD6zjXorRuxBuWUfTZXGC1LPzFdg7FMUH8Uwa-g9Bdg,710
37
+ sigma/tools/adapter.py,sha256=2ChjA4I7wUVA26NBeGGddSOFeRp4_C-hikb4OpNzFF8,1238
38
+ sigma/tools/backtest.py,sha256=xYunp_dm46uGBw0pxNcWsSh4UuLmE1xuaHvWzzmcGv4,53869
39
+ sigma/tools/library.py,sha256=Yn1I9ro8Ifp1x4mtVp1uXGf3qYtQQjR4kUlv1bDFEPc,70933
40
+ sigma/tools/registry.py,sha256=SuFT22TsaVXgboiAalCVXHOdg2FV_Vy-v5H3FFdLdm4,4072
41
+ sigma/utils/extraction.py,sha256=vmSnDzrP_rUrYM_iUpDTFOGAtp6I5Ff_Z6RYR_SH9Og,2806
42
+ sigma_terminal-3.5.0.dist-info/METADATA,sha256=Q0E5P7IBXYvcAJX-f1wWC2Je6Ww8g7kHCAA1ZAWPrec,6227
43
+ sigma_terminal-3.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
44
+ sigma_terminal-3.5.0.dist-info/entry_points.txt,sha256=lFpcHMWvr4jUIO-MRrBwKhxWp-AIsRJDaWMU4dOQzlw,121
45
+ sigma_terminal-3.5.0.dist-info/licenses/LICENSE,sha256=YGf6UbSNXayxJnonOYohaDbbV1yZQfQ1wyStkTuHS6w,1099
46
+ sigma_terminal-3.5.0.dist-info/RECORD,,