feat: 全面SSH中转代理 + mimo-v2.5-pro支持
- Yahoo Finance: 跳过本地限流,直接走SSH中转 - StockTwits: 直连403时自动fallback到SSH中转 - Reddit: 网络不可达时自动fallback到SSH中转 - Polymarket: 网络不可达时自动fallback到SSH中转 - FRED: 配置API Key (825283926dd016ea66e96cc919e047da) - .env: 新增FRED_API_KEY和OPENAI_COMPATIBLE_API_KEY - test_xiaomi.py: 小米mimo-v2.5-pro测试脚本
This commit is contained in:
1 parent
51d057e2c9
commit
f8a47cb473
6 files changed
+76
-32
No files matched your search
@@ -0,0 +1,31 @@
|
|||||||
|
"""使用小米 mimo-v2.5-pro 模型运行 TradingAgents 示例"""
|
||||||
|
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
|
||||||
|
# 使用 openai_compatible 对接小米 API
|
||||||
|
config["llm_provider"] = "openai_compatible"
|
||||||
|
config["backend_url"] = "https://token-plan-cn.xiaomimimo.com/v1"
|
||||||
|
config["deep_think_llm"] = "mimo-v2.5-pro"
|
||||||
|
config["quick_think_llm"] = "mimo-v2.5-pro"
|
||||||
|
|
||||||
|
# 设置 API Key(也可通过环境变量 OPENAI_COMPATIBLE_API_KEY)
|
||||||
|
import os
|
||||||
|
os.environ["OPENAI_COMPATIBLE_API_KEY"] = "tp-ce6eaqg1gh1uev46i4oexh4sahloyfo2hfpxuc2n9m7yl9dd"
|
||||||
|
|
||||||
|
# 减少辩论轮数加速测试
|
||||||
|
config["max_debate_rounds"] = 1
|
||||||
|
config["max_risk_discuss_rounds"] = 1
|
||||||
|
|
||||||
|
print("配置完成,开始运行 TradingAgents...")
|
||||||
|
print(f"Provider: {config['llm_provider']}")
|
||||||
|
print(f"Backend: {config['backend_url']}")
|
||||||
|
print(f"Model: {config['deep_think_llm']}")
|
||||||
|
|
||||||
|
ta = TradingAgentsGraph(debug=True, config=config)
|
||||||
|
|
||||||
|
# 测试分析茅台(A股)
|
||||||
|
_, decision = ta.propagate("600519.SS", "2026-01-15")
|
||||||
|
print("\n=== 交易决策 ===")
|
||||||
|
print(decision)
|
||||||
@@ -13,8 +13,12 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from .stockstats_utils import _get_ssh_config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
GAMMA_BASE = "https://gamma-api.polymarket.com"
|
GAMMA_BASE = "https://gamma-api.polymarket.com"
|
||||||
@@ -27,11 +31,28 @@ DEFAULT_LIMIT = 6
|
|||||||
|
|
||||||
|
|
||||||
def _request(path: str, params: dict) -> dict:
|
def _request(path: str, params: dict) -> dict:
|
||||||
response = requests.get(
|
url = f"{GAMMA_BASE}/{path}"
|
||||||
f"{GAMMA_BASE}/{path}", params=params, timeout=REQUEST_TIMEOUT
|
try:
|
||||||
)
|
response = requests.get(url, params=params, timeout=REQUEST_TIMEOUT)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
|
except requests.RequestException:
|
||||||
|
# Fallback: fetch through SSH proxy
|
||||||
|
logger.info("Polymarket direct failed, trying SSH proxy for %s...", path)
|
||||||
|
query = "&".join(f"{k}={v}" for k, v in params.items())
|
||||||
|
full_url = f"{url}?{query}"
|
||||||
|
host, port, password = _get_ssh_config()
|
||||||
|
cmd = [
|
||||||
|
"sshpass", "-p", password,
|
||||||
|
"ssh", "-o", "StrictHostKeyChecking=no",
|
||||||
|
"-o", "ConnectTimeout=15",
|
||||||
|
"-p", str(port), f"root@{host}",
|
||||||
|
f'curl -s "{full_url}"'
|
||||||
|
]
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=REQUEST_TIMEOUT)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise requests.RequestException(f"SSH proxy failed: {result.stderr}")
|
||||||
|
return json.loads(result.stdout)
|
||||||
|
|
||||||
|
|
||||||
def _parse_json_list(value) -> list:
|
def _parse_json_list(value) -> list:
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from urllib.parse import urlencode
|
|||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
from .symbol_utils import crypto_base
|
from .symbol_utils import crypto_base
|
||||||
|
from .stockstats_utils import _fetch_via_ssh
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -123,7 +124,12 @@ def _fetch_subreddit_rss(
|
|||||||
except (OSError, http.client.HTTPException, ET.ParseError) as exc:
|
except (OSError, http.client.HTTPException, ET.ParseError) as exc:
|
||||||
# OSError covers URLError/TimeoutError/connection resets; HTTPException
|
# OSError covers URLError/TimeoutError/connection resets; HTTPException
|
||||||
# covers chunked-transfer errors (IncompleteRead/BadStatusLine, #1024).
|
# covers chunked-transfer errors (IncompleteRead/BadStatusLine, #1024).
|
||||||
logger.warning("Reddit RSS fetch failed for r/%s · %s: %s", sub, ticker, exc)
|
logger.warning("Reddit RSS direct fetch failed for r/%s · %s: %s, trying SSH proxy...", sub, ticker, exc)
|
||||||
|
try:
|
||||||
|
proxy_data = _fetch_via_ssh(url, timeout=timeout)
|
||||||
|
root = ET.fromstring(proxy_data.encode() if isinstance(proxy_data, str) else proxy_data)
|
||||||
|
except Exception as proxy_exc:
|
||||||
|
logger.warning("Reddit RSS proxy also failed for r/%s · %s: %s", sub, ticker, proxy_exc)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
posts = []
|
posts = []
|
||||||
|
|||||||
@@ -321,33 +321,17 @@ def load_ohlcv(symbol: str, curr_date: str) -> pd.DataFrame:
|
|||||||
if use_alpha_vantage:
|
if use_alpha_vantage:
|
||||||
downloaded = _load_ohlcv_alpha_vantage(symbol, curr_date)
|
downloaded = _load_ohlcv_alpha_vantage(symbol, curr_date)
|
||||||
else:
|
else:
|
||||||
downloaded = None
|
# Skip local Yahoo Finance, go directly through SSH proxy
|
||||||
try:
|
logger.info(f"Yahoo Finance: fetching {canonical} via SSH proxy...")
|
||||||
raw = yf_retry(lambda: yf.download(
|
|
||||||
canonical,
|
|
||||||
start=start_str,
|
|
||||||
end=end_str,
|
|
||||||
multi_level_index=False,
|
|
||||||
progress=False,
|
|
||||||
auto_adjust=True,
|
|
||||||
))
|
|
||||||
downloaded = _ensure_date_column(raw.reset_index())
|
|
||||||
except Exception as yf_err:
|
|
||||||
pass # Will try proxy below
|
|
||||||
|
|
||||||
# If local yfinance failed or returned empty, try SSH proxy
|
|
||||||
if downloaded is None or downloaded.empty or "Close" not in downloaded.columns:
|
|
||||||
if downloaded is None or downloaded.empty:
|
|
||||||
logger.warning(f"Yahoo Finance local failed, trying SSH proxy...")
|
|
||||||
try:
|
try:
|
||||||
downloaded = _yf_download_via_proxy(canonical, start_str, end_str)
|
downloaded = _yf_download_via_proxy(canonical, start_str, end_str)
|
||||||
except Exception as proxy_err:
|
except Exception as proxy_err:
|
||||||
raise NoMarketDataError(
|
raise NoMarketDataError(
|
||||||
symbol, canonical, f"Yahoo Finance proxy also failed: {proxy_err}"
|
symbol, canonical, f"Yahoo Finance proxy failed: {proxy_err}"
|
||||||
) from proxy_err
|
) from proxy_err
|
||||||
if downloaded.empty:
|
if downloaded.empty:
|
||||||
raise NoMarketDataError(
|
raise NoMarketDataError(
|
||||||
symbol, canonical, f"Yahoo Finance proxy also returned no data"
|
symbol, canonical, f"Yahoo Finance proxy returned no data"
|
||||||
)
|
)
|
||||||
if downloaded.empty or "Close" not in downloaded.columns:
|
if downloaded.empty or "Close" not in downloaded.columns:
|
||||||
raise NoMarketDataError(
|
raise NoMarketDataError(
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import logging
|
|||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
from .symbol_utils import crypto_base
|
from .symbol_utils import crypto_base
|
||||||
|
from .stockstats_utils import _fetch_via_ssh
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -54,7 +55,12 @@ def fetch_stocktwits_messages(ticker: str, limit: int = 30, timeout: float = 10.
|
|||||||
except (OSError, http.client.HTTPException, json.JSONDecodeError) as exc:
|
except (OSError, http.client.HTTPException, json.JSONDecodeError) as exc:
|
||||||
# OSError covers URLError/TimeoutError/connection resets; HTTPException
|
# OSError covers URLError/TimeoutError/connection resets; HTTPException
|
||||||
# covers chunked-transfer errors (IncompleteRead/BadStatusLine, #1024).
|
# covers chunked-transfer errors (IncompleteRead/BadStatusLine, #1024).
|
||||||
logger.warning("StockTwits fetch failed for %s: %s", ticker, exc)
|
logger.warning("StockTwits direct fetch failed for %s: %s, trying SSH proxy...", ticker, exc)
|
||||||
|
try:
|
||||||
|
proxy_data = _fetch_via_ssh(url, timeout=timeout)
|
||||||
|
data = json.loads(proxy_data)
|
||||||
|
except Exception as proxy_exc:
|
||||||
|
logger.warning("StockTwits proxy also failed for %s: %s", ticker, proxy_exc)
|
||||||
return f"<stocktwits unavailable: {type(exc).__name__}>"
|
return f"<stocktwits unavailable: {type(exc).__name__}>"
|
||||||
|
|
||||||
messages = data.get("messages", []) if isinstance(data, dict) else []
|
messages = data.get("messages", []) if isinstance(data, dict) else []
|
||||||
|
|||||||
@@ -36,17 +36,13 @@ def get_YFin_data_online(
|
|||||||
# end_date row (and the current day when end_date is today). Request one day
|
# end_date row (and the current day when end_date is today). Request one day
|
||||||
# past end_date so the requested range is actually inclusive (#986/#987).
|
# past end_date so the requested range is actually inclusive (#986/#987).
|
||||||
end_inclusive = (end_dt + relativedelta(days=1)).strftime("%Y-%m-%d")
|
end_inclusive = (end_dt + relativedelta(days=1)).strftime("%Y-%m-%d")
|
||||||
try:
|
# Skip local Yahoo Finance (rate-limited), go directly through SSH proxy
|
||||||
data = yf_retry(lambda: ticker.history(start=start_date, end=end_inclusive))
|
logger.info(f"Yahoo Finance: fetching {canonical} via SSH proxy...")
|
||||||
except Exception:
|
|
||||||
# Fallback: use SSH proxy via foreign server
|
|
||||||
logger.warning(f"Yahoo Finance local failed for {symbol}, trying SSH proxy...")
|
|
||||||
proxy_df = _yf_download_via_proxy(canonical, start_date, end_inclusive)
|
proxy_df = _yf_download_via_proxy(canonical, start_date, end_inclusive)
|
||||||
if proxy_df.empty:
|
if proxy_df.empty:
|
||||||
raise NoMarketDataError(
|
raise NoMarketDataError(
|
||||||
symbol, canonical, f"no rows between {start_date} and {end_date} (proxy also failed)"
|
symbol, canonical, f"no rows between {start_date} and {end_date} (proxy failed)"
|
||||||
)
|
)
|
||||||
# Convert to match expected format
|
|
||||||
proxy_df = proxy_df.set_index("Date")
|
proxy_df = proxy_df.set_index("Date")
|
||||||
data = proxy_df
|
data = proxy_df
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user