77 _check_stationarity ,
88 _create_lagged_features ,
99 _difference_series ,
10+ _integrate_ar_coefficients ,
11+ fit_ar_model ,
1012)
1113
12- significane = 0.05
14+ significance = 0.05
1315expected_coeff_count = 3 # For p=2: Intercept + 2 Lags
1416expected_length_lagged = 3
1517
1618
17- def test_check_stationarity ():
19+ def test_check_stationarity_stationary ():
20+ """Test ADF stationarity check on a stationary time series."""
1821 rng = np .random .default_rng (12 )
1922 df = pd .DataFrame ({"price" : rng .normal (0 , 1 , 100 )})
20- stationary , p_value = _check_stationarity (df , "price" , significance = significane )
21- assert bool (stationary ) is True
2223
23- # 2. Non-stationary series
24- df ["price" ] = np .linspace (1 , 100 , 100 ) + rng .normal (0 , 0.5 , 100 )
25- stationary , p_value = _check_stationarity (df , "price" , significance = significane )
26- assert bool (stationary ) is False
27- assert p_value > significane
24+ stationary , p_value , test_statistic = _check_stationarity (df , "price" , significance )
25+
26+ assert all (
27+ [
28+ bool (stationary ) is True ,
29+ isinstance (p_value , float ),
30+ isinstance (test_statistic , float ),
31+ ]
32+ )
33+
34+
35+ def test_check_stationarity_non_stationary ():
36+ """Test ADF stationarity check on a nonstationary time series."""
37+ rng = np .random .default_rng (12 )
38+ df = pd .DataFrame ({"price" : np .linspace (1 , 100 , 100 ) + rng .normal (0 , 0.5 , 100 )})
39+
40+ stationary , p_value , test_statistic = _check_stationarity (df , "price" , significance )
41+
42+ assert all (
43+ [
44+ bool (stationary ) is False ,
45+ p_value > significance ,
46+ isinstance (test_statistic , float ),
47+ ]
48+ )
2849
2950
3051def test_difference_series ():
52+ """Test differencing function for correct column creation and values."""
3153 df = pd .DataFrame ({"price" : [100 , 101 , 103 , 106 ]})
3254 result = _difference_series (df .copy (), "price" )
33- assert "diff_price" in result .columns
34- # Check that the second value of the differenced series equals 1.
35- assert result ["diff_price" ].iloc [1 ] == 1
55+
56+ assert all (["diff_price" in result .columns , result ["diff_price" ].iloc [1 ] == 1 ])
3657
3758
3859def test_create_lagged_features ():
60+ """Test creation of lagged features for an AR model."""
3961 df = pd .DataFrame ({"price" : [10 , 20 , 30 , 40 , 50 ]})
4062 result = _create_lagged_features (df .copy (), "price" , 2 )
41- assert "price_lag1" in result .columns
42- assert "price_lag2" in result .columns
43- assert len (result ) == expected_length_lagged
63+
64+ assert all (
65+ [
66+ "price_lag1" in result .columns ,
67+ "price_lag2" in result .columns ,
68+ len (result ) == expected_length_lagged ,
69+ ]
70+ )
4471
4572
4673def test_ar_model_output ():
74+ """Test output structure and type of AR model fitting function."""
4775 rng = np .random .default_rng (312 )
4876
4977 dates = pd .date_range ("2020-01-01" , periods = 10 , freq = "D" )
@@ -62,11 +90,11 @@ def test_ar_model_output():
6290
6391 coeffs = _ar_model (df , "price" , 2 )
6492
65- assert len (coeffs ) == expected_coeff_count
66- assert isinstance (coeffs , np .ndarray )
93+ assert all ([len (coeffs ) == expected_coeff_count , isinstance (coeffs , np .ndarray )])
6794
6895
6996def test_ar_model_correctness ():
97+ """Test correctness of AR model coefficients against a reference implementation."""
7098 rng = np .random .default_rng (2 )
7199 dates = pd .date_range ("2020-01-01" , periods = 100 , freq = "D" )
72100 df = pd .DataFrame (
@@ -89,3 +117,82 @@ def test_ar_model_correctness():
89117 f"Reference: { reference_coeffs } \n "
90118 f"Difference: { custom_coeffs - reference_coeffs } "
91119 )
120+
121+
122+ def test_integrate_ar_coefficients_no_differencing ():
123+ """Test integration of AR coefficients when no differencing is applied."""
124+ diff_coeffs = np .array ([0.5 , - 0.2 , 0.1 ])
125+
126+ result = _integrate_ar_coefficients (diff_coeffs , differenced = False )
127+ expected_lags = ["Intercept" , "Lag 1" , "Lag 2" ]
128+ assert all (
129+ [
130+ np .allclose (result ["coefficient" ].to_numpy (), diff_coeffs ),
131+ list (result ["lag" ]) == expected_lags ,
132+ ]
133+ )
134+
135+
136+ def test_integrate_ar_coefficients_with_differencing ():
137+ """Test integration of AR coefficients when differencing is applied."""
138+ diff_coeffs = np .array ([0.5 , - 0.2 , 0.1 ])
139+
140+ result = _integrate_ar_coefficients (diff_coeffs , differenced = True )
141+
142+ expected_coeffs = np .array ([0.5 , 1 - 0.2 , - 0.2 - 0.1 , - 0.1 ])
143+ expected_lags = ["Intercept" , "Lag 1" , "Lag 2" , "Lag 3" ]
144+ assert all (
145+ [
146+ np .allclose (result ["coefficient" ].to_numpy (), expected_coeffs ),
147+ list (result ["lag" ]) == expected_lags ,
148+ ]
149+ )
150+
151+
152+ def test_fit_ar_model_stationary_series ():
153+ """Test AR model fitting on a stationary time series."""
154+ rng = np .random .default_rng (42 )
155+ df = pd .DataFrame (
156+ {"close_price" : np .sin (np .linspace (0 , 10 , 100 )) + rng .normal (0 , 0.1 , 100 )}
157+ )
158+
159+ result = fit_ar_model (df , column = "close_price" , p = 2 )
160+
161+ assert result ["differenced" ] is False
162+
163+
164+ def test_fit_ar_model_non_stationary_series ():
165+ """Test AR model fitting on a non-stationary time series."""
166+ rng = np .random .default_rng (42 )
167+ df = pd .DataFrame (
168+ {"close_price" : np .cumsum (np .linspace (0.1 , 1 , 100 )) + rng .normal (0 , 0.1 , 100 )}
169+ )
170+
171+ result = fit_ar_model (df , column = "close_price" , p = 2 )
172+
173+ assert result ["differenced" ] is True
174+
175+
176+ def test_fit_ar_model_coefficient_shape ():
177+ """Test if the number of coefficients matches AR order + intercept."""
178+ rng = np .random .default_rng (42 )
179+ df = pd .DataFrame (
180+ {"close_price" : np .cos (np .linspace (0 , 10 , 100 )) + rng .normal (0 , 0.1 , 100 )}
181+ )
182+
183+ p = 3
184+ result = fit_ar_model (df , column = "close_price" , p = p )
185+
186+ assert result ["coefficients" ].shape [0 ] == p + 1
187+
188+
189+ def test_fit_ar_model_p_value ():
190+ """Test if p-value is included in the result dictionary."""
191+ rng = np .random .default_rng (42 )
192+ df = pd .DataFrame (
193+ {"close_price" : np .exp (np .linspace (0 , 2 , 100 )) + rng .normal (0 , 0.1 , 100 )}
194+ )
195+
196+ result = fit_ar_model (df , column = "close_price" , p = 2 )
197+
198+ assert isinstance (result ["p_value" ], float )
0 commit comments