Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9be43b827 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
@@ -0,0 +1,91 @@
|
||||
import unittest
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from models.model_training import walk_forward_splits
|
||||
|
||||
class TestModelTraining(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# Create a simple dummy sequence (e.g., numbers 0 to 9)
|
||||
self.X = pd.DataFrame({'feature': np.arange(10)})
|
||||
self.y = pd.Series(np.arange(10))
|
||||
|
||||
def test_walk_forward_splits_basic(self):
|
||||
"""Test basic chronological splitting with default n_splits=3 on n=10."""
|
||||
# For n=10, n_splits=3, fold_size = 10 // (3 + 1) = 2
|
||||
# Fold 1: Train [0:2], Test [2:4]
|
||||
# Fold 2: Train [0:4], Test [4:6]
|
||||
# Fold 3: Train [0:6], Test [6:8]
|
||||
folds = walk_forward_splits(self.X, self.y, n_splits=3)
|
||||
|
||||
self.assertEqual(len(folds), 3)
|
||||
|
||||
# Fold 1
|
||||
X_train_1, y_train_1, X_test_1, y_test_1 = folds[0]
|
||||
self.assertEqual(len(X_train_1), 2)
|
||||
self.assertEqual(len(X_test_1), 2)
|
||||
self.assertTrue(np.array_equal(X_train_1['feature'].values, [0, 1]))
|
||||
self.assertTrue(np.array_equal(X_test_1['feature'].values, [2, 3]))
|
||||
|
||||
# Fold 2
|
||||
X_train_2, y_train_2, X_test_2, y_test_2 = folds[1]
|
||||
self.assertEqual(len(X_train_2), 4)
|
||||
self.assertEqual(len(X_test_2), 2)
|
||||
self.assertTrue(np.array_equal(X_train_2['feature'].values, [0, 1, 2, 3]))
|
||||
self.assertTrue(np.array_equal(X_test_2['feature'].values, [4, 5]))
|
||||
|
||||
# Fold 3
|
||||
X_train_3, y_train_3, X_test_3, y_test_3 = folds[2]
|
||||
self.assertEqual(len(X_train_3), 6)
|
||||
self.assertEqual(len(X_test_3), 2)
|
||||
self.assertTrue(np.array_equal(X_train_3['feature'].values, [0, 1, 2, 3, 4, 5]))
|
||||
self.assertTrue(np.array_equal(X_test_3['feature'].values, [6, 7]))
|
||||
|
||||
def test_walk_forward_splits_varying_n_splits(self):
|
||||
"""Test varying number of splits."""
|
||||
# For n=10, n_splits=4, fold_size = 10 // (4 + 1) = 2
|
||||
folds = walk_forward_splits(self.X, self.y, n_splits=4)
|
||||
self.assertEqual(len(folds), 4)
|
||||
|
||||
# Last fold: Train [0:8], Test [8:10]
|
||||
X_train_last, _, X_test_last, _ = folds[-1]
|
||||
self.assertEqual(len(X_train_last), 8)
|
||||
self.assertEqual(len(X_test_last), 2)
|
||||
self.assertEqual(X_test_last['feature'].iloc[-1], 9)
|
||||
|
||||
def test_walk_forward_splits_remainder(self):
|
||||
"""Test dataset size that doesn't divide perfectly."""
|
||||
# n=11, n_splits=3, fold_size = 11 // (3 + 1) = 2
|
||||
# Fold 1: Train [0:2], Test [2:4]
|
||||
# Fold 2: Train [0:4], Test [4:6]
|
||||
# Fold 3: Train [0:6], Test [6:8]
|
||||
X_11 = pd.DataFrame({'feature': np.arange(11)})
|
||||
y_11 = pd.Series(np.arange(11))
|
||||
|
||||
folds = walk_forward_splits(X_11, y_11, n_splits=3)
|
||||
self.assertEqual(len(folds), 3)
|
||||
|
||||
# Check last fold bounds
|
||||
X_train_last, _, X_test_last, _ = folds[-1]
|
||||
self.assertEqual(len(X_train_last), 6)
|
||||
self.assertEqual(len(X_test_last), 2)
|
||||
self.assertTrue(np.array_equal(X_test_last['feature'].values, [6, 7]))
|
||||
|
||||
def test_walk_forward_splits_end_bounds(self):
|
||||
"""Test case where end_test is capped at n."""
|
||||
# n=5, n_splits=2, fold_size = 5 // 3 = 1
|
||||
# Fold 1: Train [0:1], Test [1:2]
|
||||
# Fold 2: Train [0:2], Test [2:3]
|
||||
X_5 = pd.DataFrame({'feature': np.arange(5)})
|
||||
y_5 = pd.Series(np.arange(5))
|
||||
folds = walk_forward_splits(X_5, y_5, n_splits=2)
|
||||
self.assertEqual(len(folds), 2)
|
||||
|
||||
X_train_last, _, X_test_last, _ = folds[-1]
|
||||
self.assertEqual(len(X_train_last), 2)
|
||||
self.assertEqual(len(X_test_last), 1)
|
||||
self.assertTrue(np.array_equal(X_test_last['feature'].values, [2]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user