From b5c145730a51b3cf297cef2028578aaa969ce2ee Mon Sep 17 00:00:00 2001 From: gavindiaz Date: Wed, 8 Jul 2026 06:44:00 +0000 Subject: [PATCH] Add test for MQL5 bridge --- tests/test_mql5.py | 131 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/test_mql5.py diff --git a/tests/test_mql5.py b/tests/test_mql5.py new file mode 100644 index 0000000..a545215 --- /dev/null +++ b/tests/test_mql5.py @@ -0,0 +1,131 @@ +"""Tests for MQL5 GlobalVariable bridge.""" + +import responses +import pytest + +import mt5bridge_ccxt + + +class TestMql5Bridge: + @responses.activate + def test_list(self, exchange_config): + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/gvar", + json={"data": [ + {"name": "AT_Trend_XAUUSD", "value": 1.0}, + {"name": "AT_Buy_XAUUSD", "value": 1.0}, + ], "count": 2, "format": "json"}, + status=200, + ) + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + gvars = ex.mql5.list() + assert len(gvars) == 2 + assert gvars[0]["name"] == "AT_Trend_XAUUSD" + + @responses.activate + def test_get_existing(self, exchange_config): + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/gvar/AT_Trend_XAUUSD", + json={"name": "AT_Trend_XAUUSD", "value": 1.0}, + status=200, + ) + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + assert ex.mql5.get("AT_Trend_XAUUSD") == 1.0 + + @responses.activate + def test_get_missing_returns_default(self, exchange_config): + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/gvar/MISSING", + json={"detail": "Not found"}, status=404, + ) + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + assert ex.mql5.get("MISSING") is None + assert ex.mql5.get("MISSING", default=42) == 42 + + @responses.activate + def test_set(self, exchange_config): + responses.add( + responses.POST, + "http://mock-mt5bridge:8080/gvar/MY_KEY", + json={"name": "MY_KEY", "value": 75.5}, + status=200, + ) + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + result = ex.mql5.set("MY_KEY", 75.5) + assert result["name"] == "MY_KEY" + + @responses.activate + def test_alpha_trend_signal(self, exchange_config): + # Mock 5 GV lookups + gv_data = { + "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Alpha": {"name": "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Alpha", "value": 4180.0}, + "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Offset": {"name": "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Offset", "value": 4178.0}, + "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Trend": {"name": "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Trend", "value": 1.0}, + "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Buy": {"name": "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Buy", "value": 1.0}, + "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Sell": {"name": "AT_XAUUSDc_PERIOD_H1_L14_A1.0_C0_S1_Sell", "value": 0.0}, + } + for path, payload in gv_data.items(): + responses.add( + responses.GET, + f"http://mock-mt5bridge:8080/gvar/{path}", + json=payload, status=200, + ) + + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + signal = ex.mql5.alpha_trend_signal("XAUUSDc", "H1", length=14, atr_mult=1.0) + assert signal["alpha"] == 4180.0 + assert signal["trend"] == 1.0 + assert signal["buy"] == 1.0 + assert signal["sell"] == 0.0 + + +class TestTimeframeConversion: + def test_to_mt5(self): + from mt5bridge_ccxt.timeframe import to_mt5 + assert to_mt5("1m") == "TIMEFRAME_M1" + assert to_mt5("1h") == "TIMEFRAME_H1" + assert to_mt5("1d") == "TIMEFRAME_D1" + + def test_to_mt5_invalid(self): + from mt5bridge_ccxt.timeframe import to_mt5 + with pytest.raises(ValueError): + to_mt5("2h") + + def test_to_ccxt(self): + from mt5bridge_ccxt.timeframe import to_ccxt + assert to_ccxt("TIMEFRAME_M1") == "1m" + assert to_ccxt("TIMEFRAME_H1") == "1h" + assert to_ccxt("TIMEFRAME_D1") == "1d" + + +class TestSymbolConversion: + def test_to_mt5_with_slash(self): + from mt5bridge_ccxt.symbol import to_mt5_symbol + assert to_mt5_symbol("XAU/USD") == "XAUUSD" + assert to_mt5_symbol("EUR/USD") == "EURUSD" + + def test_to_mt5_already_mt5(self): + from mt5bridge_ccxt.symbol import to_mt5_symbol + assert to_mt5_symbol("XAUUSDc") == "XAUUSDc" + + def test_to_mt5_with_suffix(self): + from mt5bridge_ccxt.symbol import to_mt5_symbol + assert to_mt5_symbol("XAU/USD", default_suffix="c") == "XAUUSDc" + + def test_to_ccxt_simple(self): + from mt5bridge_ccxt.symbol import to_ccxt_symbol + assert to_ccxt_symbol("XAUUSD") == "XAU/USD" + assert to_ccxt_symbol("EURUSD") == "EUR/USD" + + def test_to_ccxt_with_suffix(self): + from mt5bridge_ccxt.symbol import to_ccxt_symbol + assert to_ccxt_symbol("XAUUSDc") == "XAU/USD" + assert to_ccxt_symbol("EURUSDc") == "EUR/USD" + + def test_to_ccxt_with_explicit_quote(self): + from mt5bridge_ccxt.symbol import to_ccxt_symbol + # Ambiguous case: split on explicit quote + assert to_ccxt_symbol("XAUUSD", quote="USD") == "XAU/USD"