volengine 0.9.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- volengine/__init__.py +37 -0
- volengine/_dcc.py +264 -0
- volengine/_diagnostics.py +51 -0
- volengine/_fit.py +209 -0
- volengine/_forecast.py +65 -0
- volengine/_lib/libvolengine.dll +0 -0
- volengine/_native.py +329 -0
- volengine/_simulation.py +70 -0
- volengine/_spec.py +240 -0
- volengine/api.py +417 -0
- volengine/py.typed +0 -0
- volengine-0.9.0.dist-info/METADATA +6 -0
- volengine-0.9.0.dist-info/RECORD +14 -0
- volengine-0.9.0.dist-info/WHEEL +4 -0
volengine/_native.py
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"""ctypes bindings that mirror include/volengine/volengine.h."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ctypes
|
|
6
|
+
import os
|
|
7
|
+
from collections.abc import Callable, Mapping
|
|
8
|
+
from contextlib import ExitStack
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from types import TracebackType
|
|
11
|
+
from typing import Any, cast
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
from numpy.typing import NDArray
|
|
15
|
+
|
|
16
|
+
VE_ABI_VERSION = 0
|
|
17
|
+
VE_INTERNAL_ERROR = 5
|
|
18
|
+
INT32_MIN = -(2**31)
|
|
19
|
+
INT32_MAX = 2**31 - 1
|
|
20
|
+
LIBRARY_ENV = "VOLENGINE_LIB"
|
|
21
|
+
LIBRARY_DIRECTORY = Path(__file__).resolve().parent / "_lib"
|
|
22
|
+
LIBRARY_NAMES = ("libvolengine.dll", "volengine.dll", "libvolengine.so", "libvolengine.dylib")
|
|
23
|
+
|
|
24
|
+
_HANDLE = ctypes.c_void_p
|
|
25
|
+
_OUT_HANDLE = ctypes.POINTER(ctypes.c_void_p)
|
|
26
|
+
_STATUS = ctypes.c_int32
|
|
27
|
+
_SIZE = ctypes.c_size_t
|
|
28
|
+
_I32 = ctypes.c_int32
|
|
29
|
+
_DOUBLE = ctypes.c_double
|
|
30
|
+
_OUT_DOUBLE = ctypes.POINTER(ctypes.c_double)
|
|
31
|
+
_OUT_SIZE = ctypes.POINTER(ctypes.c_size_t)
|
|
32
|
+
_OUT_I32 = ctypes.POINTER(ctypes.c_int32)
|
|
33
|
+
_OUT_VIEW = ctypes.POINTER(ctypes.POINTER(ctypes.c_double))
|
|
34
|
+
_OUT_TEXT = ctypes.POINTER(ctypes.c_char_p)
|
|
35
|
+
|
|
36
|
+
_SCALAR_CRITERION = [_HANDLE, _I32, _OUT_DOUBLE]
|
|
37
|
+
_VIEW = [_HANDLE, _OUT_VIEW, _OUT_SIZE]
|
|
38
|
+
_SE_VALUES = [_HANDLE, _I32, _HANDLE]
|
|
39
|
+
|
|
40
|
+
PROTOTYPES: dict[str, tuple[Any, list[Any]]] = {
|
|
41
|
+
"ve_dcc_spec_create": (_STATUS, [_I32, _OUT_HANDLE]),
|
|
42
|
+
"ve_dcc_spec_set_order": (_STATUS, [_HANDLE, _I32, _I32]),
|
|
43
|
+
"ve_dcc_spec_set_dist": (_STATUS, [_HANDLE, _I32]),
|
|
44
|
+
"ve_dcc_spec_set_groups": (_STATUS, [_HANDLE, ctypes.POINTER(_I32), _SIZE]),
|
|
45
|
+
"ve_dcc_spec_set_fixed": (_STATUS, [_HANDLE, ctypes.c_char_p, _DOUBLE]),
|
|
46
|
+
"ve_dcc_spec_set_start": (_STATUS, [_HANDLE, ctypes.c_char_p, _DOUBLE]),
|
|
47
|
+
"ve_dcc_spec_set_copula": (_STATUS, [_HANDLE, _I32]),
|
|
48
|
+
"ve_dcc_spec_set_static_method": (_STATUS, [_HANDLE, _I32]),
|
|
49
|
+
"ve_dcc_options_create": (_STATUS, [_OUT_HANDLE]),
|
|
50
|
+
"ve_dcc_options_set_standard_errors": (_STATUS, [_HANDLE, _I32]),
|
|
51
|
+
"ve_dcc_batch_create": (_STATUS, [_OUT_HANDLE]),
|
|
52
|
+
"ve_dcc_batch_set_specs": (_STATUS, [_HANDLE, ctypes.POINTER(_HANDLE), _SIZE]),
|
|
53
|
+
"ve_dcc_batch_set_fits": (_STATUS, [_HANDLE, ctypes.POINTER(_HANDLE), _SIZE]),
|
|
54
|
+
"ve_dcc_batch_set_options": (_STATUS, [_HANDLE, _HANDLE]),
|
|
55
|
+
"ve_dcc_fit_batch": (_STATUS, [_HANDLE, _HANDLE, ctypes.POINTER(_HANDLE)]),
|
|
56
|
+
"ve_dcc_fit_standard_errors": (_STATUS, [_HANDLE, _HANDLE, ctypes.POINTER(_HANDLE), _SIZE, _OUT_HANDLE]),
|
|
57
|
+
"ve_dcc_fit_status": (_STATUS, [_HANDLE, _OUT_I32]),
|
|
58
|
+
"ve_dcc_fit_nobs": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
59
|
+
"ve_dcc_fit_series": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
60
|
+
"ve_dcc_fit_param_count": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
61
|
+
"ve_dcc_fit_param_name": (_STATUS, [_HANDLE, _SIZE, _OUT_TEXT]),
|
|
62
|
+
"ve_dcc_fit_estimates": (_STATUS, [_HANDLE, _HANDLE]),
|
|
63
|
+
"ve_dcc_fit_std_errors": (_STATUS, _SE_VALUES),
|
|
64
|
+
"ve_dcc_fit_t_values": (_STATUS, _SE_VALUES),
|
|
65
|
+
"ve_dcc_fit_p_values": (_STATUS, _SE_VALUES),
|
|
66
|
+
"ve_dcc_fit_loglik": (_STATUS, [_HANDLE, _OUT_DOUBLE]),
|
|
67
|
+
"ve_dcc_fit_criterion": (_STATUS, [_HANDLE, _I32, _I32, _OUT_DOUBLE]),
|
|
68
|
+
"ve_dcc_fit_correlation": (_STATUS, _VIEW),
|
|
69
|
+
"ve_dcc_fit_covariance": (_STATUS, _VIEW),
|
|
70
|
+
"ve_dcc_spec_free": (None, [_HANDLE]),
|
|
71
|
+
"ve_dcc_options_free": (None, [_HANDLE]),
|
|
72
|
+
"ve_dcc_batch_free": (None, [_HANDLE]),
|
|
73
|
+
"ve_dcc_fit_free": (None, [_HANDLE]),
|
|
74
|
+
"ve_fit_ljung_box": (_STATUS, [_HANDLE, _I32, _SIZE, _SIZE, _HANDLE]),
|
|
75
|
+
"ve_fit_arch_lm": (_STATUS, [_HANDLE, _SIZE, _SIZE, _HANDLE]),
|
|
76
|
+
"ve_fit_nyblom": (_STATUS, [_HANDLE, _HANDLE, _OUT_DOUBLE, _HANDLE]),
|
|
77
|
+
"ve_nyblom_critical": (_STATUS, [_SIZE, _HANDLE]),
|
|
78
|
+
"ve_fit_sign_bias": (_STATUS, [_HANDLE, _HANDLE]),
|
|
79
|
+
"ve_fit_gof": (_STATUS, [_HANDLE, _SIZE, _HANDLE]),
|
|
80
|
+
"ve_abi_version": (_I32, []),
|
|
81
|
+
"ve_last_error": (ctypes.c_char_p, []),
|
|
82
|
+
"ve_context_create": (_STATUS, [_OUT_HANDLE]),
|
|
83
|
+
"ve_context_set_threads": (_STATUS, [_HANDLE, _I32]),
|
|
84
|
+
"ve_context_threads": (_STATUS, [_HANDLE, _OUT_I32]),
|
|
85
|
+
"ve_context_free": (None, [_HANDLE]),
|
|
86
|
+
"ve_spec_create": (_STATUS, [_I32, _OUT_HANDLE]),
|
|
87
|
+
"ve_spec_set_order": (_STATUS, [_HANDLE, _I32, _I32]),
|
|
88
|
+
"ve_spec_set_arma": (_STATUS, [_HANDLE, _I32, _I32]),
|
|
89
|
+
"ve_spec_set_dist": (_STATUS, [_HANDLE, _I32]),
|
|
90
|
+
"ve_spec_set_include_mean": (_STATUS, [_HANDLE, _I32]),
|
|
91
|
+
"ve_spec_set_mxreg": (_STATUS, [_HANDLE, _I32]),
|
|
92
|
+
"ve_spec_set_vxreg": (_STATUS, [_HANDLE, _I32]),
|
|
93
|
+
"ve_spec_set_archm": (_STATUS, [_HANDLE, _I32]),
|
|
94
|
+
"ve_spec_set_arfima": (_STATUS, [_HANDLE, _I32]),
|
|
95
|
+
"ve_spec_set_fixed": (_STATUS, [_HANDLE, ctypes.c_char_p, _DOUBLE]),
|
|
96
|
+
"ve_spec_set_start": (_STATUS, [_HANDLE, ctypes.c_char_p, _DOUBLE]),
|
|
97
|
+
"ve_spec_set_variance_targeting": (_STATUS, [_HANDLE, _I32]),
|
|
98
|
+
"ve_spec_validate": (_STATUS, [_HANDLE]),
|
|
99
|
+
"ve_spec_free": (None, [_HANDLE]),
|
|
100
|
+
"ve_fit_options_create": (_STATUS, [_OUT_HANDLE]),
|
|
101
|
+
"ve_fit_options_set_max_iter": (_STATUS, [_HANDLE, _I32]),
|
|
102
|
+
"ve_fit_options_set_tolerance": (_STATUS, [_HANDLE, _DOUBLE]),
|
|
103
|
+
"ve_fit_options_set_var_init": (_STATUS, [_HANDLE, _I32]),
|
|
104
|
+
"ve_fit_options_set_standard_errors": (_STATUS, [_HANDLE, _I32]),
|
|
105
|
+
"ve_fit_options_free": (None, [_HANDLE]),
|
|
106
|
+
"ve_panel_create": (_STATUS, [_HANDLE, _SIZE, _SIZE, _OUT_HANDLE]),
|
|
107
|
+
"ve_panel_set_strides": (_STATUS, [_HANDLE, ctypes.c_ssize_t, ctypes.c_ssize_t]),
|
|
108
|
+
"ve_panel_set_ranges": (_STATUS, [_HANDLE, _HANDLE, _HANDLE]),
|
|
109
|
+
"ve_panel_free": (None, [_HANDLE]),
|
|
110
|
+
"ve_batch_create": (_STATUS, [_OUT_HANDLE]),
|
|
111
|
+
"ve_batch_set_specs": (_STATUS, [_HANDLE, ctypes.POINTER(ctypes.c_void_p), _SIZE]),
|
|
112
|
+
"ve_batch_set_panel": (_STATUS, [_HANDLE, _HANDLE]),
|
|
113
|
+
"ve_batch_set_jobs": (_STATUS, [_HANDLE, _HANDLE, _HANDLE, _SIZE]),
|
|
114
|
+
"ve_batch_set_options": (_STATUS, [_HANDLE, _HANDLE]),
|
|
115
|
+
"ve_batch_set_regressors": (_STATUS, [_HANDLE, _HANDLE, _HANDLE, _SIZE]),
|
|
116
|
+
"ve_batch_job_count": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
117
|
+
"ve_batch_free": (None, [_HANDLE]),
|
|
118
|
+
"ve_fit_batch": (_STATUS, [_HANDLE, _HANDLE, ctypes.POINTER(ctypes.c_void_p)]),
|
|
119
|
+
"ve_fit_status": (_STATUS, [_HANDLE, _OUT_I32]),
|
|
120
|
+
"ve_fit_nobs": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
121
|
+
"ve_fit_param_count": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
122
|
+
"ve_fit_param_name": (_STATUS, [_HANDLE, _SIZE, _OUT_TEXT]),
|
|
123
|
+
"ve_fit_estimates": (_STATUS, [_HANDLE, _HANDLE]),
|
|
124
|
+
"ve_fit_std_errors": (_STATUS, _SE_VALUES),
|
|
125
|
+
"ve_fit_t_values": (_STATUS, _SE_VALUES),
|
|
126
|
+
"ve_fit_p_values": (_STATUS, _SE_VALUES),
|
|
127
|
+
"ve_loglik": (_STATUS, [_HANDLE, _OUT_DOUBLE]),
|
|
128
|
+
"ve_aic": (_STATUS, _SCALAR_CRITERION),
|
|
129
|
+
"ve_bic": (_STATUS, _SCALAR_CRITERION),
|
|
130
|
+
"ve_hqic": (_STATUS, _SCALAR_CRITERION),
|
|
131
|
+
"ve_sic": (_STATUS, _SCALAR_CRITERION),
|
|
132
|
+
"ve_fit_sigma": (_STATUS, _VIEW),
|
|
133
|
+
"ve_fit_residuals": (_STATUS, _VIEW),
|
|
134
|
+
"ve_fit_std_residuals": (_STATUS, _VIEW),
|
|
135
|
+
"ve_fit_fitted": (_STATUS, _VIEW),
|
|
136
|
+
"ve_fit_free": (None, [_HANDLE]),
|
|
137
|
+
"ve_forecast_create": (_STATUS, [_HANDLE, _SIZE, _HANDLE, _HANDLE, _OUT_HANDLE]),
|
|
138
|
+
"ve_forecast_horizon": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
139
|
+
"ve_forecast_sigma": (_STATUS, _VIEW),
|
|
140
|
+
"ve_forecast_mean": (_STATUS, _VIEW),
|
|
141
|
+
"ve_forecast_free": (None, [_HANDLE]),
|
|
142
|
+
"ve_sim_options_create": (_STATUS, [_SIZE, _SIZE, ctypes.c_uint64, _OUT_HANDLE]),
|
|
143
|
+
"ve_sim_options_set_regressors": (_STATUS, [_HANDLE, _HANDLE, _HANDLE]),
|
|
144
|
+
"ve_sim_options_free": (None, [_HANDLE]),
|
|
145
|
+
"ve_simulate_fit": (_STATUS, [_HANDLE, _HANDLE, _HANDLE, _OUT_HANDLE]),
|
|
146
|
+
"ve_simulate_spec": (_STATUS, [_HANDLE, _HANDLE, _HANDLE, _OUT_HANDLE]),
|
|
147
|
+
"ve_sim_paths": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
148
|
+
"ve_sim_horizon": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
149
|
+
"ve_sim_returns": (_STATUS, _VIEW),
|
|
150
|
+
"ve_sim_sigma": (_STATUS, _VIEW),
|
|
151
|
+
"ve_sim_free": (None, [_HANDLE]),
|
|
152
|
+
"ve_dcc_future_create": (_STATUS, [_SIZE, _SIZE, _OUT_HANDLE]),
|
|
153
|
+
"ve_dcc_future_set": (_STATUS, [_HANDLE, _SIZE, _HANDLE, _HANDLE]),
|
|
154
|
+
"ve_dcc_future_free": (None, [_HANDLE]),
|
|
155
|
+
"ve_dcc_forecast_create": (_STATUS, [_HANDLE, _SIZE, _HANDLE, _OUT_HANDLE]),
|
|
156
|
+
"ve_dcc_forecast_horizon": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
157
|
+
"ve_dcc_forecast_series": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
158
|
+
"ve_dcc_forecast_correlation": (_STATUS, _VIEW),
|
|
159
|
+
"ve_dcc_forecast_covariance": (_STATUS, _VIEW),
|
|
160
|
+
"ve_dcc_forecast_sigma": (_STATUS, _VIEW),
|
|
161
|
+
"ve_dcc_forecast_mean": (_STATUS, _VIEW),
|
|
162
|
+
"ve_dcc_forecast_free": (None, [_HANDLE]),
|
|
163
|
+
"ve_sim_options_set_correlations": (_STATUS, [_HANDLE, _I32]),
|
|
164
|
+
"ve_simulate_dcc": (_STATUS, [_HANDLE, _HANDLE, _HANDLE, _HANDLE, _OUT_HANDLE]),
|
|
165
|
+
"ve_dcc_sim_paths": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
166
|
+
"ve_dcc_sim_horizon": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
167
|
+
"ve_dcc_sim_series": (_STATUS, [_HANDLE, _OUT_SIZE]),
|
|
168
|
+
"ve_dcc_sim_returns": (_STATUS, _VIEW),
|
|
169
|
+
"ve_dcc_sim_sigma": (_STATUS, _VIEW),
|
|
170
|
+
"ve_dcc_sim_correlation": (_STATUS, _VIEW),
|
|
171
|
+
"ve_dcc_sim_covariance": (_STATUS, _VIEW),
|
|
172
|
+
"ve_dcc_sim_free": (None, [_HANDLE]),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class VolEngineError(Exception):
|
|
177
|
+
"""A native call failed; `status` is the VE_* code and the message comes from ve_last_error()."""
|
|
178
|
+
|
|
179
|
+
def __init__(self, status: int, message: str) -> None:
|
|
180
|
+
super().__init__(message)
|
|
181
|
+
self.status = status
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def locate_library(override: str | None, directory: Path) -> Path:
|
|
185
|
+
if override:
|
|
186
|
+
path = Path(override)
|
|
187
|
+
if not path.is_file():
|
|
188
|
+
raise ImportError(f"{LIBRARY_ENV} points to {override}, which is not a file")
|
|
189
|
+
return path
|
|
190
|
+
for name in LIBRARY_NAMES:
|
|
191
|
+
if (directory / name).is_file():
|
|
192
|
+
return directory / name
|
|
193
|
+
raise ImportError(
|
|
194
|
+
f"VolEngine native library not found: set {LIBRARY_ENV} to the library file, "
|
|
195
|
+
f"or place one of {', '.join(LIBRARY_NAMES)} in {directory}"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def load_library(environ: Mapping[str, str], directory: Path) -> ctypes.CDLL:
|
|
200
|
+
path = locate_library(environ.get(LIBRARY_ENV), directory)
|
|
201
|
+
try:
|
|
202
|
+
library = ctypes.CDLL(str(path))
|
|
203
|
+
except OSError as error:
|
|
204
|
+
raise ImportError(f"cannot load the VolEngine native library {path}: {error}") from error
|
|
205
|
+
check_abi(library, path)
|
|
206
|
+
declare_prototypes(library)
|
|
207
|
+
return library
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def check_abi(library: ctypes.CDLL, path: Path) -> None:
|
|
211
|
+
try:
|
|
212
|
+
declare_function(library, "ve_abi_version")
|
|
213
|
+
except AttributeError as error:
|
|
214
|
+
raise ImportError(f"{path} does not export ve_abi_version, it is not a VolEngine library") from error
|
|
215
|
+
abi = library.ve_abi_version()
|
|
216
|
+
if abi != VE_ABI_VERSION:
|
|
217
|
+
raise ImportError(f"{path} has ABI version {abi}, this package needs {VE_ABI_VERSION}")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def declare_function(library: ctypes.CDLL, name: str) -> None:
|
|
221
|
+
restype, argtypes = PROTOTYPES[name]
|
|
222
|
+
function = getattr(library, name)
|
|
223
|
+
function.restype = restype
|
|
224
|
+
function.argtypes = argtypes
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def declare_prototypes(library: ctypes.CDLL) -> None:
|
|
228
|
+
for name in PROTOTYPES:
|
|
229
|
+
declare_function(library, name)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
lib = load_library(os.environ, LIBRARY_DIRECTORY)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def last_error() -> str:
|
|
236
|
+
message = cast(bytes | None, lib.ve_last_error())
|
|
237
|
+
if message is None:
|
|
238
|
+
return ""
|
|
239
|
+
return message.decode("utf-8", errors="replace")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def int32(value: int, name: str) -> int:
|
|
243
|
+
"""`value` checked to fit a C int32_t, which ctypes would otherwise wrap around silently."""
|
|
244
|
+
if not INT32_MIN <= value <= INT32_MAX:
|
|
245
|
+
raise ValueError(f"{name} must fit in a 32-bit signed integer, got {value}")
|
|
246
|
+
return value
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def check(status: int) -> None:
|
|
250
|
+
if status != 0:
|
|
251
|
+
raise VolEngineError(status, last_error())
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class Handle:
|
|
255
|
+
"""Owns one native handle and frees it exactly once."""
|
|
256
|
+
|
|
257
|
+
def __init__(self, pointer: int | None, free: Callable[[int], None]) -> None:
|
|
258
|
+
self._pointer: int | None = pointer
|
|
259
|
+
self._free = free
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def pointer(self) -> int:
|
|
263
|
+
if self._pointer is None:
|
|
264
|
+
raise ValueError("the native handle is already closed")
|
|
265
|
+
return self._pointer
|
|
266
|
+
|
|
267
|
+
def close(self) -> None:
|
|
268
|
+
pointer, self._pointer = self._pointer, None
|
|
269
|
+
if pointer is not None:
|
|
270
|
+
self._free(pointer)
|
|
271
|
+
|
|
272
|
+
def __enter__(self) -> Handle:
|
|
273
|
+
return self
|
|
274
|
+
|
|
275
|
+
def __exit__(
|
|
276
|
+
self,
|
|
277
|
+
exc_type: type[BaseException] | None,
|
|
278
|
+
exc: BaseException | None,
|
|
279
|
+
traceback: TracebackType | None,
|
|
280
|
+
) -> None:
|
|
281
|
+
self.close()
|
|
282
|
+
|
|
283
|
+
def __del__(self) -> None:
|
|
284
|
+
self.close()
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def create_handle(create: Callable[..., int], free: Callable[[int], None], *args: Any) -> Handle:
|
|
288
|
+
out = ctypes.c_void_p()
|
|
289
|
+
check(create(*args, ctypes.byref(out)))
|
|
290
|
+
if out.value is None:
|
|
291
|
+
raise VolEngineError(VE_INTERNAL_ERROR, "the native create call returned a null handle")
|
|
292
|
+
return Handle(out.value, free)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def read_scalar(ctype: Any, function: Callable[..., int], *args: Any) -> Any:
|
|
296
|
+
out = ctype()
|
|
297
|
+
check(function(*args, ctypes.byref(out)))
|
|
298
|
+
return out.value
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
ELEMENT_BYTES = np.dtype(np.float64).itemsize
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def open_panel(stack: ExitStack, array: NDArray[np.float64]) -> Handle:
|
|
305
|
+
panel = stack.enter_context(
|
|
306
|
+
create_handle(lib.ve_panel_create, lib.ve_panel_free, array.ctypes.data, array.shape[0], array.shape[1])
|
|
307
|
+
)
|
|
308
|
+
stride_t, stride_n = (stride // ELEMENT_BYTES for stride in array.strides)
|
|
309
|
+
check(lib.ve_panel_set_strides(panel.pointer, stride_t, stride_n))
|
|
310
|
+
return panel
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def read_only(array: NDArray[np.float64]) -> NDArray[np.float64]:
|
|
314
|
+
array.flags.writeable = False
|
|
315
|
+
return array
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def native_view(owner: object, function: Callable[..., int], pointer: int) -> NDArray[np.float64]:
|
|
319
|
+
"""The read-only view a VE_* view function returns for `pointer`; it keeps `owner` (and its handle) alive."""
|
|
320
|
+
data = ctypes.POINTER(ctypes.c_double)()
|
|
321
|
+
length = ctypes.c_size_t()
|
|
322
|
+
check(function(pointer, ctypes.byref(data), ctypes.byref(length)))
|
|
323
|
+
if length.value == 0:
|
|
324
|
+
return read_only(np.empty(0, dtype=np.float64))
|
|
325
|
+
address = ctypes.cast(data, ctypes.c_void_p).value
|
|
326
|
+
assert address is not None
|
|
327
|
+
buffer = (ctypes.c_double * length.value).from_address(address)
|
|
328
|
+
setattr(buffer, "_owner", owner)
|
|
329
|
+
return read_only(np.frombuffer(buffer, dtype=np.float64))
|
volengine/_simulation.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Simulated paths over ve_sim handles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ctypes
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from numpy.typing import NDArray
|
|
9
|
+
|
|
10
|
+
from ._native import Handle, lib, native_view, read_scalar
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DccSimulation:
|
|
14
|
+
"""Paths simulated from a DCC fit, after its last observation.
|
|
15
|
+
|
|
16
|
+
`returns` and `sigma` are read-only arrays of shape (paths, horizon, N); `R` and `H` of shape (paths, horizon,
|
|
17
|
+
N, N) exist only for a simulation run with `correlations=True` (VolEngineError otherwise). Each step takes R
|
|
18
|
+
from the exact recursion, draws a shock of covariance R (a Gaussian scale mixture for the mvt and the
|
|
19
|
+
mvlaplace), and turns it into the standardized shock of each series: itself in a DCC, or through the copula and
|
|
20
|
+
the margin of the series in a Copula-DCC. Path p reads only the stream (seed, p): the same seed gives the same
|
|
21
|
+
paths for any number of threads, within one version of the library. The simulation does not depend on its fit.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, handle: Handle) -> None:
|
|
25
|
+
self._handle = handle
|
|
26
|
+
self._shape = (
|
|
27
|
+
read_scalar(ctypes.c_size_t, lib.ve_dcc_sim_paths, handle.pointer),
|
|
28
|
+
read_scalar(ctypes.c_size_t, lib.ve_dcc_sim_horizon, handle.pointer),
|
|
29
|
+
read_scalar(ctypes.c_size_t, lib.ve_dcc_sim_series, handle.pointer),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def returns(self) -> NDArray[np.float64]:
|
|
34
|
+
return native_view(self, lib.ve_dcc_sim_returns, self._handle.pointer).reshape(self._shape)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def sigma(self) -> NDArray[np.float64]:
|
|
38
|
+
return native_view(self, lib.ve_dcc_sim_sigma, self._handle.pointer).reshape(self._shape)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def R(self) -> NDArray[np.float64]:
|
|
42
|
+
return native_view(self, lib.ve_dcc_sim_correlation, self._handle.pointer).reshape(*self._shape, self._shape[2])
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def H(self) -> NDArray[np.float64]:
|
|
46
|
+
return native_view(self, lib.ve_dcc_sim_covariance, self._handle.pointer).reshape(*self._shape, self._shape[2])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Simulation:
|
|
50
|
+
"""Paths simulated from a fit (after its last observation) or from a spec with every parameter fixed.
|
|
51
|
+
|
|
52
|
+
`returns` and `sigma` are read-only arrays of shape (paths, horizon): row p is path p, `returns` the simulated
|
|
53
|
+
series and `sigma` its conditional standard deviation. The same seed gives the same paths for any number of
|
|
54
|
+
threads, but only within one version of the library. The simulation does not depend on its source.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, handle: Handle) -> None:
|
|
58
|
+
self._handle = handle
|
|
59
|
+
self._shape = (
|
|
60
|
+
read_scalar(ctypes.c_size_t, lib.ve_sim_paths, handle.pointer),
|
|
61
|
+
read_scalar(ctypes.c_size_t, lib.ve_sim_horizon, handle.pointer),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def returns(self) -> NDArray[np.float64]:
|
|
66
|
+
return native_view(self, lib.ve_sim_returns, self._handle.pointer).reshape(self._shape)
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def sigma(self) -> NDArray[np.float64]:
|
|
70
|
+
return native_view(self, lib.ve_sim_sigma, self._handle.pointer).reshape(self._shape)
|
volengine/_spec.py
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Model specifications and fit options, validated eagerly through the native library."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from dataclasses import KW_ONLY, dataclass, field
|
|
7
|
+
from typing import NoReturn
|
|
8
|
+
|
|
9
|
+
from ._native import Handle, check, create_handle, int32, lib
|
|
10
|
+
|
|
11
|
+
MODELS = {"sgarch": 0, "egarch": 1, "gjrgarch": 2, "aparch": 3, "igarch": 4, "csgarch": 5}
|
|
12
|
+
SUBMODELS = {
|
|
13
|
+
"garch": 6,
|
|
14
|
+
"tgarch": 7,
|
|
15
|
+
"avgarch": 8,
|
|
16
|
+
"ngarch": 9,
|
|
17
|
+
"nagarch": 10,
|
|
18
|
+
"aparch": 11,
|
|
19
|
+
"gjrgarch": 12,
|
|
20
|
+
"allgarch": 13,
|
|
21
|
+
}
|
|
22
|
+
DISTRIBUTIONS = {"norm": 0, "std": 1, "ged": 2, "sstd": 3, "sged": 4, "nig": 5, "ghyp": 6, "jsu": 7}
|
|
23
|
+
VAR_INITS = {"sample": 0, "backcast": 1}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def code_of(table: dict[str, int], kind: str, name: str) -> int:
|
|
27
|
+
if name not in table:
|
|
28
|
+
listed = list(table)
|
|
29
|
+
if kind == "model":
|
|
30
|
+
listed.append("fgarch")
|
|
31
|
+
raise ValueError(f"unknown {kind} {name!r}; expected one of {sorted(listed)}")
|
|
32
|
+
return table[name]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _FrozenDict(dict[str, float]):
|
|
36
|
+
"""A dict that refuses every mutation; unlike MappingProxyType it pickles, deep-copies and works with asdict."""
|
|
37
|
+
|
|
38
|
+
def _refuse(self, *args: object, **kwargs: object) -> NoReturn:
|
|
39
|
+
raise TypeError(f"{type(self).__name__} is read-only")
|
|
40
|
+
|
|
41
|
+
__setitem__ = __delitem__ = clear = pop = popitem = setdefault = update = __ior__ = _refuse
|
|
42
|
+
|
|
43
|
+
def __reduce__(self) -> tuple[type[_FrozenDict], tuple[dict[str, float]]]:
|
|
44
|
+
return (type(self), (dict(self),))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def frozen_values(values: Mapping[str, float]) -> Mapping[str, float]:
|
|
48
|
+
return _FrozenDict({name: float(value) for name, value in values.items()})
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def encoded_name(name: str) -> bytes:
|
|
52
|
+
if "\0" in name:
|
|
53
|
+
raise ValueError(f"parameter name {name!r} contains a NUL byte")
|
|
54
|
+
return name.encode()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class Spec:
|
|
59
|
+
"""Model specification. Unknown names raise ValueError, native rejections VolEngineError.
|
|
60
|
+
|
|
61
|
+
`p` is the ARCH order (number of alpha terms, lagged squared residuals) and `q` the GARCH order
|
|
62
|
+
(number of beta terms, lagged variances), as in arch's `p` and `q` and in rugarch's
|
|
63
|
+
`garchOrder = c(alpha order, beta order)` (rugarch calls those orders q and p, the other way
|
|
64
|
+
round). `arma` is the ARMA(m, n) order of the conditional mean. Orders are limited to 1..6 for
|
|
65
|
+
`p` and `q` and 0..6 for `arma` (VE_MAX_ORDER).
|
|
66
|
+
|
|
67
|
+
`model` is one of "sgarch", "egarch", "gjrgarch", "aparch", "igarch", "csgarch" and "fgarch".
|
|
68
|
+
"fgarch" requires `submodel`, one of "garch", "tgarch", "avgarch", "ngarch", "nagarch", "aparch",
|
|
69
|
+
"gjrgarch" and "allgarch"; every other model rejects it. The iGARCH `beta_q` is derived
|
|
70
|
+
(1 - sum of alphas - the other betas), not estimated: it has a name and a value, its standard error
|
|
71
|
+
is NaN and the criteria count the estimated parameters only.
|
|
72
|
+
|
|
73
|
+
`dist` is one of "norm", "std", "ged", "sstd", "sged", "nig", "ghyp" and "jsu", all standardized to
|
|
74
|
+
zero mean and unit variance. Distribution parameters come last in the fit names, in the order `skew`,
|
|
75
|
+
`shape`, `ghlambda`: "std" has `shape` (nu > 2), "ged" has `shape` (nu > 0); "sstd" and "sged" are
|
|
76
|
+
Fernandez-Steel skewed versions of those kernels with `skew` xi > 0 and the same `shape`; "nig" and
|
|
77
|
+
"ghyp" are the generalized hyperbolic in the standardized (rho, zeta) parametrization with `skew` rho
|
|
78
|
+
in (-1, 1) and `shape` zeta in (0, 1e6] ("ghyp" adds `ghlambda`, a real number; "nig" fixes it at
|
|
79
|
+
-1/2); "jsu" is Johnson SU with `skew` nu (a real number) and `shape` tau > 0. The "sstd" `skew` is
|
|
80
|
+
xi, not arch's Hansen skewness lambda in (-1, 1): xi = sqrt((1 + lambda) / (1 - lambda)), and the
|
|
81
|
+
standard error of lambda follows by the delta method, d xi / d lambda = 1 / (xi * (1 - lambda)**2);
|
|
82
|
+
the other way, lambda = (xi**2 - 1) / (xi**2 + 1) and SE(lambda) = SE(xi) * 4 * xi / (xi**2 + 1)**2.
|
|
83
|
+
|
|
84
|
+
Past zeta = 1e6 double precision no longer standardizes "nig" and "ghyp" (by then a normal to an
|
|
85
|
+
excess kurtosis of order 1 / zeta, 1.5e-5 for nig), and the log-likelihood is -inf there. On
|
|
86
|
+
near-normal data their fits drive zeta up, where rho and zeta are barely identified: the Hessian is
|
|
87
|
+
then often not positive definite, and every standard error is NaN.
|
|
88
|
+
|
|
89
|
+
Every parameter is estimated, fixed or derived. `fixed` maps parameter names (those of `Fit.names`:
|
|
90
|
+
"mu", "ar1", "omega", "alpha1", "beta1", "gamma1", "eta11", "skew", "shape", ...) to values the
|
|
91
|
+
fit keeps: they are not optimized, their standard errors are NaN and the criteria do not count them.
|
|
92
|
+
A derived parameter (the iGARCH `beta_q`, and `omega` under variance targeting) is a function of
|
|
93
|
+
the others: it has a name and a value, NaN standard errors, and is not counted either. `start`
|
|
94
|
+
maps names to starting values that replace the defaults; a start value for a derived parameter is
|
|
95
|
+
ignored, so `dict(zip(fit.names, fit.coef().estimate))` is a valid warm start. A start value for a
|
|
96
|
+
name that is also in `fixed` is ignored, because fixed wins: `Spec(fixed=..., start=dict(zip(fit.names,
|
|
97
|
+
fit.coef().estimate)))` is a valid warm start. A name with a NUL character is a ValueError. If the
|
|
98
|
+
starting point is outside the model's domain, the fit ends "failed" with NaN. A spec with every parameter fixed does not optimize: the fit evaluates the model
|
|
99
|
+
at the fixed point and is "converged" when the log-likelihood is finite.
|
|
100
|
+
|
|
101
|
+
`variance_targeting=True` makes `omega` derived: it is computed inside the likelihood from the
|
|
102
|
+
residuals of the current mean parameters over the whole sample (m2 = mean of e_t**2, P the
|
|
103
|
+
persistence): omega = m2 * (1 - P) for sgarch and gjrgarch (P = sum(alpha) + sum(beta), plus
|
|
104
|
+
pi * sum(gamma) with pi = P(z < 0) for gjrgarch); omega = log(m2) * (1 - sum(beta)) for egarch;
|
|
105
|
+
omega = mean(|e_t|**delta) * (1 - P) for aparch and fgarch, with delta the power and
|
|
106
|
+
P = sum(alpha_i * kappa_i) + sum(beta). The standard errors of the other parameters come from the
|
|
107
|
+
likelihood in which omega is a function of them (as in rugarch), not from the two-step covariance
|
|
108
|
+
of Francq, Horvath and Zakoian (2011).
|
|
109
|
+
|
|
110
|
+
`mxreg` and `vxreg` are the numbers of mean and variance regressor columns (0..8, VE_MAX_REGRESSORS) and
|
|
111
|
+
`archm` is ARCH-in-mean: 0 none, 1 adds xi * sigma_t to the mean, 2 adds xi * sigma_t**2. Their parameters are
|
|
112
|
+
named, in order, "mu", "ar1".., "ma1".., "archm", "mxreg1".., "omega", ... and "vxreg1".. before "skew". The
|
|
113
|
+
data go to `Context.fit(..., mxreg=, vxreg=)`. Mean: m_t = mu + sum(delta_k * x_t,k) + xi * sigma_t**p and
|
|
114
|
+
d_t = r_t - m_t; the ARMA acts on d_t, and the pre-sample residuals (for var_init "sample" and variance
|
|
115
|
+
targeting) are those with xi = 0. Variance: omega becomes omega + sum(zeta_k * v_t,k) in the scale of the
|
|
116
|
+
model (sigma**2, log sigma**2 or sigma**delta; in csgarch it enters q_t). Under variance targeting
|
|
117
|
+
omega = target - sum(zeta_k * mean(v_k)). With var_init "backcast" and `mxreg`, the backcast uses the
|
|
118
|
+
residuals of the OLS of r on [1 (with a mean), X], as arch does. Persistence < 1 is always enforced, unlike
|
|
119
|
+
rugarch, which drops it when there is `vxreg`; a sigma**2 <= 0 gives a log-likelihood of -inf.
|
|
120
|
+
|
|
121
|
+
`arfima=True` is rugarch's ARFIMA mean: the parameter "arfima", named after "ma1".. (where "archm" would be;
|
|
122
|
+
a spec cannot have both), is d in (1e-8, 0.5). The ARMA residuals e_t become
|
|
123
|
+
y_t = sum(pi_k * e_(t-k), k = 0..t), pi_0 = 1, pi_k = pi_(k-1) * (k - 1 - d) / k, the (1 - L)**d truncated at
|
|
124
|
+
the start of the series, at a cost of O(T**2); y_t replaces e_t everywhere after.
|
|
125
|
+
|
|
126
|
+
Rejected with VolEngineError (the message names the problem): a name the spec does not have
|
|
127
|
+
(`fixed={"shpe": 5.0}`, or "shape" under dist "norm"), fixing the iGARCH `beta_q` or `omega` under
|
|
128
|
+
variance targeting (both derived), variance targeting with "igarch" or "csgarch", and a csgarch
|
|
129
|
+
with `eta21` fixed and a free `beta` (fixing it together with every `beta` is accepted).
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
model: str = "sgarch"
|
|
133
|
+
_: KW_ONLY
|
|
134
|
+
p: int = 1
|
|
135
|
+
q: int = 1
|
|
136
|
+
arma: tuple[int, int] = (0, 0)
|
|
137
|
+
dist: str = "norm"
|
|
138
|
+
include_mean: bool = True
|
|
139
|
+
submodel: str | None = None
|
|
140
|
+
fixed: Mapping[str, float] = field(default_factory=dict)
|
|
141
|
+
start: Mapping[str, float] = field(default_factory=dict)
|
|
142
|
+
variance_targeting: bool = False
|
|
143
|
+
mxreg: int = 0
|
|
144
|
+
vxreg: int = 0
|
|
145
|
+
archm: int = 0
|
|
146
|
+
arfima: bool = False
|
|
147
|
+
|
|
148
|
+
def __post_init__(self) -> None:
|
|
149
|
+
object.__setattr__(self, "fixed", frozen_values(self.fixed))
|
|
150
|
+
object.__setattr__(self, "start", frozen_values(self.start))
|
|
151
|
+
self.native_handle().close()
|
|
152
|
+
object.__setattr__(self, "arma", tuple(self.arma))
|
|
153
|
+
|
|
154
|
+
def __hash__(self) -> int:
|
|
155
|
+
return hash(
|
|
156
|
+
(
|
|
157
|
+
self.model,
|
|
158
|
+
self.p,
|
|
159
|
+
self.q,
|
|
160
|
+
tuple(self.arma),
|
|
161
|
+
self.dist,
|
|
162
|
+
self.include_mean,
|
|
163
|
+
self.submodel,
|
|
164
|
+
frozenset(self.fixed.items()),
|
|
165
|
+
frozenset(self.start.items()),
|
|
166
|
+
self.variance_targeting,
|
|
167
|
+
self.mxreg,
|
|
168
|
+
self.vxreg,
|
|
169
|
+
self.archm,
|
|
170
|
+
self.arfima,
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def arma_orders(self) -> tuple[int, int]:
|
|
175
|
+
arma = self.arma
|
|
176
|
+
if not isinstance(arma, tuple | list) or len(arma) != 2 or not all(type(i) is int for i in arma):
|
|
177
|
+
raise ValueError(f"arma must be a pair of integers (m, n), got {arma!r}")
|
|
178
|
+
return int32(arma[0], "arma m"), int32(arma[1], "arma n")
|
|
179
|
+
|
|
180
|
+
def model_code(self) -> int:
|
|
181
|
+
if self.model != "fgarch":
|
|
182
|
+
if self.submodel is not None:
|
|
183
|
+
raise ValueError(f"submodel is only for model 'fgarch', got model {self.model!r}")
|
|
184
|
+
return code_of(MODELS, "model", self.model)
|
|
185
|
+
if self.submodel is None:
|
|
186
|
+
raise ValueError(f"model 'fgarch' requires a submodel, one of {sorted(SUBMODELS)}")
|
|
187
|
+
return code_of(SUBMODELS, "submodel", self.submodel)
|
|
188
|
+
|
|
189
|
+
def native_handle(self) -> Handle:
|
|
190
|
+
model = self.model_code()
|
|
191
|
+
dist = code_of(DISTRIBUTIONS, "dist", self.dist)
|
|
192
|
+
arma = self.arma_orders()
|
|
193
|
+
handle = create_handle(lib.ve_spec_create, lib.ve_spec_free, model)
|
|
194
|
+
check(lib.ve_spec_set_order(handle.pointer, int32(self.p, "p"), int32(self.q, "q")))
|
|
195
|
+
check(lib.ve_spec_set_arma(handle.pointer, *arma))
|
|
196
|
+
check(lib.ve_spec_set_dist(handle.pointer, dist))
|
|
197
|
+
check(lib.ve_spec_set_include_mean(handle.pointer, int(self.include_mean)))
|
|
198
|
+
check(lib.ve_spec_set_mxreg(handle.pointer, int32(self.mxreg, "mxreg")))
|
|
199
|
+
check(lib.ve_spec_set_vxreg(handle.pointer, int32(self.vxreg, "vxreg")))
|
|
200
|
+
check(lib.ve_spec_set_archm(handle.pointer, int32(self.archm, "archm")))
|
|
201
|
+
check(lib.ve_spec_set_arfima(handle.pointer, int(self.arfima)))
|
|
202
|
+
self.apply_values(handle)
|
|
203
|
+
return handle
|
|
204
|
+
|
|
205
|
+
def apply_values(self, handle: Handle) -> None:
|
|
206
|
+
for name, value in self.fixed.items():
|
|
207
|
+
check(lib.ve_spec_set_fixed(handle.pointer, encoded_name(name), value))
|
|
208
|
+
for name, value in self.start.items():
|
|
209
|
+
check(lib.ve_spec_set_start(handle.pointer, encoded_name(name), value))
|
|
210
|
+
check(lib.ve_spec_set_variance_targeting(handle.pointer, int(self.variance_targeting)))
|
|
211
|
+
check(lib.ve_spec_validate(handle.pointer))
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass(frozen=True)
|
|
215
|
+
class FitOptions:
|
|
216
|
+
"""Optimizer settings for a fit.
|
|
217
|
+
|
|
218
|
+
standard_errors=False skips the inference at the estimate (Hessian and robust standard errors, scores,
|
|
219
|
+
Nyblom): Fit.coef() and Fit.nyblom() then raise VolEngineError, while Fit.estimate, the criteria, the series,
|
|
220
|
+
forecasts, simulations and DCC fits stay the same. Useful for a grid chosen by a criterion; refit the chosen
|
|
221
|
+
model with standard errors.
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
_: KW_ONLY
|
|
225
|
+
max_iter: int = 500
|
|
226
|
+
tol: float = 1e-6
|
|
227
|
+
var_init: str = "sample"
|
|
228
|
+
standard_errors: bool = True
|
|
229
|
+
|
|
230
|
+
def __post_init__(self) -> None:
|
|
231
|
+
self.native_handle().close()
|
|
232
|
+
|
|
233
|
+
def native_handle(self) -> Handle:
|
|
234
|
+
var_init = code_of(VAR_INITS, "var_init", self.var_init)
|
|
235
|
+
handle = create_handle(lib.ve_fit_options_create, lib.ve_fit_options_free)
|
|
236
|
+
check(lib.ve_fit_options_set_max_iter(handle.pointer, int32(self.max_iter, "max_iter")))
|
|
237
|
+
check(lib.ve_fit_options_set_tolerance(handle.pointer, self.tol))
|
|
238
|
+
check(lib.ve_fit_options_set_var_init(handle.pointer, var_init))
|
|
239
|
+
check(lib.ve_fit_options_set_standard_errors(handle.pointer, int(self.standard_errors)))
|
|
240
|
+
return handle
|