ifieryarrows commited on
Commit
269f729
·
verified ·
1 Parent(s): aa0e151

Sync from GitHub

Browse files
Files changed (3) hide show
  1. app/inference.py +32 -5
  2. app/main.py +12 -6
  3. app/settings.py +4 -0
app/inference.py CHANGED
@@ -40,22 +40,49 @@ def get_current_price(session: Session, symbol: str) -> Optional[float]:
40
  """
41
  Get the current price for a symbol.
42
 
43
- Tries yfinance live data first (15-min delayed), then falls back to DB.
 
 
 
44
  """
 
45
  import yfinance as yf
 
46
 
47
- # Try live yfinance data first
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  try:
49
  ticker = yf.Ticker(symbol)
50
  info = ticker.info
51
  live_price = info.get('regularMarketPrice') or info.get('currentPrice')
52
  if live_price is not None:
53
- logger.info(f"Using live price for {symbol}: ${live_price:.4f}")
54
  return float(live_price)
55
  except Exception as e:
56
- logger.debug(f"Could not get live price for {symbol}: {e}")
57
 
58
- # Fallback to database
59
  latest = session.query(PriceBar).filter(
60
  PriceBar.symbol == symbol
61
  ).order_by(PriceBar.date.desc()).first()
 
40
  """
41
  Get the current price for a symbol.
42
 
43
+ Priority:
44
+ 1. Twelve Data API (most reliable, no rate limit issues)
45
+ 2. yfinance live data (15-min delayed)
46
+ 3. Database fallback
47
  """
48
+ import httpx
49
  import yfinance as yf
50
+ from app.settings import get_settings
51
 
52
+ settings = get_settings()
53
+
54
+ # Try Twelve Data first (for XCU/USD copper)
55
+ if settings.twelvedata_api_key:
56
+ try:
57
+ with httpx.Client(timeout=10.0) as client:
58
+ response = client.get(
59
+ "https://api.twelvedata.com/price",
60
+ params={
61
+ "symbol": "XCU/USD",
62
+ "apikey": settings.twelvedata_api_key,
63
+ }
64
+ )
65
+ if response.status_code == 200:
66
+ data = response.json()
67
+ price = data.get("price")
68
+ if price:
69
+ logger.info(f"Using Twelve Data price for copper: ${float(price):.4f}")
70
+ return float(price)
71
+ except Exception as e:
72
+ logger.debug(f"Twelve Data price fetch failed: {e}")
73
+
74
+ # Try yfinance as fallback
75
  try:
76
  ticker = yf.Ticker(symbol)
77
  info = ticker.info
78
  live_price = info.get('regularMarketPrice') or info.get('currentPrice')
79
  if live_price is not None:
80
+ logger.info(f"Using yfinance price for {symbol}: ${live_price:.4f}")
81
  return float(live_price)
82
  except Exception as e:
83
+ logger.debug(f"yfinance price fetch failed for {symbol}: {e}")
84
 
85
+ # Final fallback to database
86
  latest = session.query(PriceBar).filter(
87
  PriceBar.symbol == symbol
88
  ).order_by(PriceBar.date.desc()).first()
app/main.py CHANGED
@@ -175,19 +175,25 @@ async def get_analysis(
175
  predicted_return = float(model.predict(dmatrix)[0])
176
 
177
  # Update with live prediction
178
- # Use DB close as prediction base (model trained on closes)
 
 
 
179
  cached['predicted_return'] = round(predicted_return, 6)
180
  cached['predicted_price'] = round(
181
- float(prediction_base) * (1 + predicted_return),
182
  4
183
  )
184
 
185
- # Update confidence bounds (based on prediction base)
 
 
 
186
  std_mult = 1.0 # 1 standard deviation
187
- cached['confidence_lower'] = round(float(prediction_base) * (1 - std_mult * abs(predicted_return)), 4)
188
- cached['confidence_upper'] = round(float(prediction_base) * (1 + std_mult * abs(predicted_return) * 2), 4)
189
 
190
- logger.info(f"LIVE prediction: close=${prediction_base:.4f}, predicted=${cached['predicted_price']:.4f} ({predicted_return*100:.2f}%)")
191
 
192
  except Exception as e:
193
  logger.error(f"Live prediction failed, using cached: {e}")
 
175
  predicted_return = float(model.predict(dmatrix)[0])
176
 
177
  # Update with live prediction
178
+ # Apply futures-spot adjustment (HG=F is ~1.5% higher than XCU/USD)
179
+ adjustment = settings.futures_spot_adjustment
180
+ adjusted_base = float(prediction_base) * adjustment
181
+
182
  cached['predicted_return'] = round(predicted_return, 6)
183
  cached['predicted_price'] = round(
184
+ adjusted_base * (1 + predicted_return),
185
  4
186
  )
187
 
188
+ # Also adjust current_price for consistency
189
+ cached['current_price'] = round(adjusted_base, 4)
190
+
191
+ # Update confidence bounds (based on adjusted base)
192
  std_mult = 1.0 # 1 standard deviation
193
+ cached['confidence_lower'] = round(adjusted_base * (1 - std_mult * abs(predicted_return)), 4)
194
+ cached['confidence_upper'] = round(adjusted_base * (1 + std_mult * abs(predicted_return) * 2), 4)
195
 
196
+ logger.info(f"LIVE prediction: HG=F=${prediction_base:.4f} -> XCU/USD≈${adjusted_base:.4f}, predicted=${cached['predicted_price']:.4f} ({predicted_return*100:.2f}%)")
197
 
198
  except Exception as e:
199
  logger.error(f"Live prediction failed, using cached: {e}")
app/settings.py CHANGED
@@ -51,6 +51,10 @@ class Settings(BaseSettings):
51
  analysis_ttl_minutes: int = 30
52
  log_level: str = "INFO"
53
 
 
 
 
 
54
  # Scheduler
55
  schedule_time: str = "02:00"
56
  tz: str = "Europe/Istanbul"
 
51
  analysis_ttl_minutes: int = 30
52
  log_level: str = "INFO"
53
 
54
+ # Futures vs Spot adjustment factor
55
+ # HG=F (futures) is ~1.5% higher than XCU/USD (spot)
56
+ futures_spot_adjustment: float = 0.985 # Multiply HG=F by this to get XCU/USD
57
+
58
  # Scheduler
59
  schedule_time: str = "02:00"
60
  tz: str = "Europe/Istanbul"