Skip to content

Commit 97a0b9f

Browse files
committed
fix: pass proxy env to ccxt loader
1 parent 8d3ae19 commit 97a0b9f

2 files changed

Lines changed: 76 additions & 1 deletion

File tree

agent/backtest/loaders/ccxt_loader.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@
3737
_CCXT_FETCH_BUDGET_S = float(os.getenv("CCXT_FETCH_BUDGET_S", "60"))
3838

3939

40+
def _first_proxy_env(*names: str) -> str:
41+
for name in names:
42+
value = os.getenv(name, "").strip()
43+
if value:
44+
return value
45+
return ""
46+
47+
48+
def _ccxt_proxy_config() -> dict[str, str]:
49+
"""Build CCXT proxy settings from conventional proxy environment variables."""
50+
all_proxy = _first_proxy_env("ALL_PROXY", "all_proxy")
51+
http_proxy = _first_proxy_env("HTTP_PROXY", "http_proxy") or all_proxy
52+
https_proxy = _first_proxy_env("HTTPS_PROXY", "https_proxy") or all_proxy or http_proxy
53+
54+
proxies: dict[str, str] = {}
55+
if http_proxy:
56+
proxies["http"] = http_proxy
57+
if https_proxy:
58+
proxies["https"] = https_proxy
59+
return proxies
60+
61+
4062
@register
4163
class DataLoader:
4264
"""CCXT-backed crypto OHLCV loader (100+ exchanges)."""
@@ -64,7 +86,12 @@ def _get_exchange(self):
6486
if exchange_cls is None:
6587
logger.warning("Unknown CCXT exchange %s, falling back to binance", exchange_id)
6688
exchange_cls = ccxt.binance
67-
return exchange_cls({"enableRateLimit": True, "timeout": _CCXT_TIMEOUT_MS})
89+
90+
config = {"enableRateLimit": True, "timeout": _CCXT_TIMEOUT_MS}
91+
proxies = _ccxt_proxy_config()
92+
if proxies:
93+
config["proxies"] = proxies
94+
return exchange_cls(config)
6895

6996
def fetch(
7097
self,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""Regression tests for CCXT proxy environment handling."""
2+
3+
from __future__ import annotations
4+
5+
import ccxt
6+
7+
from backtest.loaders.ccxt_loader import DataLoader
8+
9+
10+
class _FakeExchange:
11+
def __init__(self, config):
12+
self.config = config
13+
14+
15+
def _clear_proxy_env(monkeypatch):
16+
for name in (
17+
"HTTP_PROXY",
18+
"HTTPS_PROXY",
19+
"ALL_PROXY",
20+
"http_proxy",
21+
"https_proxy",
22+
"all_proxy",
23+
):
24+
monkeypatch.delenv(name, raising=False)
25+
26+
27+
def test_get_exchange_passes_all_proxy_to_ccxt(monkeypatch):
28+
_clear_proxy_env(monkeypatch)
29+
monkeypatch.setenv("CCXT_EXCHANGE", "binance")
30+
monkeypatch.setenv("ALL_PROXY", "socks5h://127.0.0.1:1088")
31+
monkeypatch.setattr(ccxt, "binance", _FakeExchange)
32+
33+
exchange = DataLoader()._get_exchange()
34+
35+
assert exchange.config["proxies"] == {
36+
"http": "socks5h://127.0.0.1:1088",
37+
"https": "socks5h://127.0.0.1:1088",
38+
}
39+
40+
41+
def test_get_exchange_omits_proxy_config_when_env_absent(monkeypatch):
42+
_clear_proxy_env(monkeypatch)
43+
monkeypatch.setenv("CCXT_EXCHANGE", "binance")
44+
monkeypatch.setattr(ccxt, "binance", _FakeExchange)
45+
46+
exchange = DataLoader()._get_exchange()
47+
48+
assert "proxies" not in exchange.config

0 commit comments

Comments
 (0)