Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f4e62ba57 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from features.labeling_schemes import calculate_future_returns
|
||||
|
||||
def test_calculate_future_returns_happy_path():
|
||||
# Setup data
|
||||
data = {"close": [100.0, 105.0, 102.0, 110.0, 115.0]}
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
# Test horizon 1
|
||||
result_h1 = calculate_future_returns(df.copy(), horizon=1)
|
||||
|
||||
# Expected:
|
||||
# idx 0: (105 - 100) / 100 = 0.05
|
||||
# idx 1: (102 - 105) / 105 = -0.028571
|
||||
# idx 2: (110 - 102) / 102 = 0.078431
|
||||
# idx 3: (115 - 110) / 110 = 0.045455
|
||||
# idx 4: NaN
|
||||
assert len(result_h1) == 4
|
||||
np.testing.assert_allclose(result_h1["future_returns"].iloc[0], 0.05, atol=1e-5)
|
||||
np.testing.assert_allclose(result_h1["future_returns"].iloc[1], -0.028571, atol=1e-5)
|
||||
|
||||
# Test horizon 2
|
||||
result_h2 = calculate_future_returns(df.copy(), horizon=2)
|
||||
# idx 0: (102 - 100) / 100 = 0.02
|
||||
# idx 1: (110 - 105) / 105 = 0.047619
|
||||
# idx 2: (115 - 102) / 102 = 0.127451
|
||||
# idx 3: NaN
|
||||
# idx 4: NaN
|
||||
assert len(result_h2) == 3
|
||||
np.testing.assert_allclose(result_h2["future_returns"].iloc[0], 0.02, atol=1e-5)
|
||||
np.testing.assert_allclose(result_h2["future_returns"].iloc[1], 0.047619, atol=1e-5)
|
||||
np.testing.assert_allclose(result_h2["future_returns"].iloc[2], 0.127451, atol=1e-5)
|
||||
|
||||
def test_calculate_future_returns_tiny_df():
|
||||
# Rationale: Testing with a tiny DataFrame length < horizon to see if it correctly returns empty or handles it gracefully.
|
||||
data = {"close": [100.0, 105.0]}
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
# Test horizon 5 where df length is 2
|
||||
result = calculate_future_returns(df.copy(), horizon=5)
|
||||
|
||||
# Should return empty DataFrame gracefully
|
||||
assert result.empty
|
||||
assert "future_returns" in result.columns
|
||||
|
||||
def test_calculate_future_returns_missing_close_column():
|
||||
data = {"open": [100.0, 105.0, 102.0]}
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
calculate_future_returns(df.copy(), horizon=1)
|
||||
@@ -1,74 +0,0 @@
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
# Mock MetaTrader5 before importing data_loader
|
||||
mt5_mock = MagicMock()
|
||||
sys.modules['MetaTrader5'] = mt5_mock
|
||||
|
||||
import pandas as pd
|
||||
import pytest
|
||||
from data.data_loader import get_data_mt5
|
||||
|
||||
def test_get_data_mt5_live_trading():
|
||||
"""Test get_data_mt5 when start_pos is None (live trading)."""
|
||||
# Arrange
|
||||
symbol = "BTCUSD"
|
||||
n_bars = 100
|
||||
timeframe = mt5_mock.TIMEFRAME_H1
|
||||
|
||||
# Mock return value of copy_rates_from_pos
|
||||
mock_rates = [
|
||||
{"time": 1600000000, "open": 1.0, "high": 2.0, "low": 0.5, "close": 1.5},
|
||||
{"time": 1600003600, "open": 1.5, "high": 2.5, "low": 1.0, "close": 2.0},
|
||||
]
|
||||
mt5_mock.copy_rates_from_pos.return_value = mock_rates
|
||||
|
||||
# Act
|
||||
df = get_data_mt5(symbol, n_bars, timeframe)
|
||||
|
||||
# Assert
|
||||
mt5_mock.copy_rates_from_pos.assert_called_once_with(symbol, timeframe, 0, n_bars)
|
||||
assert isinstance(df, pd.DataFrame)
|
||||
assert df.index.name == 'time'
|
||||
assert len(df) == 2
|
||||
assert "open" in df.columns
|
||||
assert df.index[0] == pd.to_datetime(1600000000, unit='s')
|
||||
|
||||
def test_get_data_mt5_backtesting():
|
||||
"""Test get_data_mt5 when start_pos is provided (backtesting)."""
|
||||
# Arrange
|
||||
mt5_mock.copy_rates_from_pos.reset_mock()
|
||||
symbol = "EURUSD"
|
||||
n_bars = 50
|
||||
timeframe = mt5_mock.TIMEFRAME_M15
|
||||
start_pos = 10
|
||||
|
||||
mock_rates = [
|
||||
{"time": 1600000000, "open": 1.1, "high": 1.2, "low": 1.0, "close": 1.15},
|
||||
]
|
||||
mt5_mock.copy_rates_from_pos.return_value = mock_rates
|
||||
|
||||
# Act
|
||||
df = get_data_mt5(symbol, n_bars, timeframe, start_pos=start_pos)
|
||||
|
||||
# Assert
|
||||
mt5_mock.copy_rates_from_pos.assert_called_once_with(symbol, timeframe, start_pos, n_bars)
|
||||
assert isinstance(df, pd.DataFrame)
|
||||
assert df.index.name == 'time'
|
||||
assert len(df) == 1
|
||||
|
||||
def test_get_data_mt5_no_data():
|
||||
"""Test get_data_mt5 when copy_rates_from_pos returns None."""
|
||||
# Arrange
|
||||
mt5_mock.copy_rates_from_pos.reset_mock()
|
||||
symbol = "INVALID"
|
||||
n_bars = 10
|
||||
timeframe = mt5_mock.TIMEFRAME_H1
|
||||
|
||||
mt5_mock.copy_rates_from_pos.return_value = None
|
||||
|
||||
# Act & Assert
|
||||
with pytest.raises(ValueError, match=f"Could not retrieve data for {symbol}"):
|
||||
get_data_mt5(symbol, n_bars, timeframe)
|
||||
|
||||
mt5_mock.copy_rates_from_pos.assert_called_once_with(symbol, timeframe, 0, n_bars)
|
||||
Reference in New Issue
Block a user