Spaces:
Running
Running
David Chan Mun POON (SG) commited on
Commit ·
2d12f96
1
Parent(s): 21fa768
feat: add absorption/scalper to vision analysis + show advanced summary in screenshot mode
Browse files- app.py +3 -0
- src/ai_analyst.py +38 -2
app.py
CHANGED
|
@@ -441,7 +441,10 @@ else:
|
|
| 441 |
image_bytes=image_bytes,
|
| 442 |
provider=ai_provider,
|
| 443 |
timeframe=tf_label,
|
|
|
|
|
|
|
| 444 |
)
|
|
|
|
| 445 |
_display_ai_result(ai_result, ai_provider)
|
| 446 |
else:
|
| 447 |
if st.button(f"Analyze {ticker}", key=f"ai_{ticker}"):
|
|
|
|
| 441 |
image_bytes=image_bytes,
|
| 442 |
provider=ai_provider,
|
| 443 |
timeframe=tf_label,
|
| 444 |
+
absorption=r.get("absorption"),
|
| 445 |
+
scalper=r.get("scalper"),
|
| 446 |
)
|
| 447 |
+
_show_advanced_summary(r.get("absorption", {}), r.get("scalper", {}))
|
| 448 |
_display_ai_result(ai_result, ai_provider)
|
| 449 |
else:
|
| 450 |
if st.button(f"Analyze {ticker}", key=f"ai_{ticker}"):
|
src/ai_analyst.py
CHANGED
|
@@ -274,17 +274,24 @@ def _call_huggingface(prompt: str) -> str:
|
|
| 274 |
VISION_PROMPT = """You are an expert technical analyst. You have been given:
|
| 275 |
1. A chart screenshot to visually analyze
|
| 276 |
2. Pre-computed indicator data from a live scanner
|
|
|
|
| 277 |
|
| 278 |
Combine BOTH the visual chart patterns you see AND the indicator data to provide a comprehensive analysis.
|
| 279 |
|
| 280 |
**Live Scanner Data:**
|
| 281 |
{scanner_data}
|
| 282 |
|
|
|
|
|
|
|
|
|
|
| 283 |
**Instructions:**
|
| 284 |
- Identify visual patterns (support/resistance lines, chart patterns, candlestick formations)
|
| 285 |
- Confirm or contradict the scanner's indicator readings with what you see on the chart
|
| 286 |
- Look for things the scanner can't detect: trendlines, channels, divergences, volume profile
|
| 287 |
-
-
|
|
|
|
|
|
|
|
|
|
| 288 |
|
| 289 |
**Respond in this exact JSON format (NO comments):**
|
| 290 |
```json
|
|
@@ -311,6 +318,8 @@ def analyze_with_screenshot(
|
|
| 311 |
image_bytes: bytes,
|
| 312 |
provider: str = "google",
|
| 313 |
timeframe: str = "Daily",
|
|
|
|
|
|
|
| 314 |
) -> dict:
|
| 315 |
"""Analyze a ticker using both live data AND a chart screenshot (vision)."""
|
| 316 |
import base64
|
|
@@ -327,7 +336,34 @@ def analyze_with_screenshot(
|
|
| 327 |
f"Confluence Score: {score}/10 | Timeframe: {timeframe}"
|
| 328 |
)
|
| 329 |
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
|
| 332 |
# Encode image
|
| 333 |
b64_image = base64.b64encode(image_bytes).decode("utf-8")
|
|
|
|
| 274 |
VISION_PROMPT = """You are an expert technical analyst. You have been given:
|
| 275 |
1. A chart screenshot to visually analyze
|
| 276 |
2. Pre-computed indicator data from a live scanner
|
| 277 |
+
3. Advanced indicator signals (Absorption Bubbles + Pro Scalper)
|
| 278 |
|
| 279 |
Combine BOTH the visual chart patterns you see AND the indicator data to provide a comprehensive analysis.
|
| 280 |
|
| 281 |
**Live Scanner Data:**
|
| 282 |
{scanner_data}
|
| 283 |
|
| 284 |
+
**Advanced Indicators:**
|
| 285 |
+
{advanced_data}
|
| 286 |
+
|
| 287 |
**Instructions:**
|
| 288 |
- Identify visual patterns (support/resistance lines, chart patterns, candlestick formations)
|
| 289 |
- Confirm or contradict the scanner's indicator readings with what you see on the chart
|
| 290 |
- Look for things the scanner can't detect: trendlines, channels, divergences, volume profile
|
| 291 |
+
- Use Absorption Bubbles data to identify support/resistance zones where volume was absorbed
|
| 292 |
+
- Use Pro Scalper signal to confirm trend direction and overbought/oversold zones
|
| 293 |
+
- CRITICAL: entry_price must NOT be the current price. Use EMA pullback levels, absorption zones, or visual support/resistance from the chart
|
| 294 |
+
- Provide specific entry, stop loss, and target prices based on chart levels + indicator data
|
| 295 |
|
| 296 |
**Respond in this exact JSON format (NO comments):**
|
| 297 |
```json
|
|
|
|
| 318 |
image_bytes: bytes,
|
| 319 |
provider: str = "google",
|
| 320 |
timeframe: str = "Daily",
|
| 321 |
+
absorption: dict = None,
|
| 322 |
+
scalper: dict = None,
|
| 323 |
) -> dict:
|
| 324 |
"""Analyze a ticker using both live data AND a chart screenshot (vision)."""
|
| 325 |
import base64
|
|
|
|
| 336 |
f"Confluence Score: {score}/10 | Timeframe: {timeframe}"
|
| 337 |
)
|
| 338 |
|
| 339 |
+
# Build advanced indicators summary
|
| 340 |
+
advanced_parts = []
|
| 341 |
+
if absorption:
|
| 342 |
+
abs_detected = absorption.get("absorption_detected", False)
|
| 343 |
+
abs_score = absorption.get("absorption_score", 0)
|
| 344 |
+
abs_bias = absorption.get("signal_bias", "neutral")
|
| 345 |
+
abs_events = absorption.get("events", [])
|
| 346 |
+
if abs_detected or abs_score > 0:
|
| 347 |
+
advanced_parts.append(
|
| 348 |
+
f"Absorption Bubbles: {abs_bias.title()} (score: {abs_score}), "
|
| 349 |
+
f"Events: {', '.join(abs_events) if abs_events else 'none'}"
|
| 350 |
+
)
|
| 351 |
+
else:
|
| 352 |
+
advanced_parts.append("Absorption Bubbles: No significant absorption detected")
|
| 353 |
+
if scalper:
|
| 354 |
+
sc_signal = scalper.get("signal", "neutral")
|
| 355 |
+
sc_conf = scalper.get("confidence", 0)
|
| 356 |
+
sc_dir = scalper.get("direction", "neutral")
|
| 357 |
+
sc_zone = scalper.get("zone", "neutral")
|
| 358 |
+
sc_reversal = scalper.get("reversal")
|
| 359 |
+
sc_str = f"Pro Scalper: {sc_signal.upper()} (confidence: {int(sc_conf*100)}%), Direction: {sc_dir}, Zone: {sc_zone}"
|
| 360 |
+
if sc_reversal:
|
| 361 |
+
sc_str += f", Reversal: {sc_reversal.replace('_', ' ')}"
|
| 362 |
+
advanced_parts.append(sc_str)
|
| 363 |
+
|
| 364 |
+
advanced_data = "\n".join(advanced_parts) if advanced_parts else "No advanced indicator data available"
|
| 365 |
+
|
| 366 |
+
prompt = VISION_PROMPT.format(scanner_data=scanner_data, advanced_data=advanced_data)
|
| 367 |
|
| 368 |
# Encode image
|
| 369 |
b64_image = base64.b64encode(image_bytes).decode("utf-8")
|