qtsurfer.api.client.models
Re-export of every generated model.
All request/response dataclasses live in
qtsurfer.api.client._generated.models; importing this module makes
them available at the shorter qtsurfer.api.client.models path.
1"""Re-export of every generated model. 2 3All request/response dataclasses live in 4``qtsurfer.api.client._generated.models``; importing this module makes 5them available at the shorter ``qtsurfer.api.client.models`` path. 6""" 7 8from qtsurfer.api.client._generated.models import * # noqa: F401,F403 9from qtsurfer.api.client._generated.models import __all__ # noqa: F401
13@_attrs_define 14class AcceptedJob: 15 """Response returned by async endpoints (`202 Accepted`). The `jobId` is deterministic for the 16 same input parameters — repeated calls with identical params return the same id. 17 18 Example: 19 {'jobId': '13RBLGQlPnfDjO6wyKSX8i'} 20 21 Attributes: 22 job_id (str): Unique job identifier; use this to poll for completion. Example: 13RBLGQlPnfDjO6wyKSX8i. 23 """ 24 25 job_id: str 26 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 27 28 def to_dict(self) -> dict[str, Any]: 29 job_id = self.job_id 30 31 field_dict: dict[str, Any] = {} 32 field_dict.update(self.additional_properties) 33 field_dict.update( 34 { 35 "jobId": job_id, 36 } 37 ) 38 39 return field_dict 40 41 @classmethod 42 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 43 d = dict(src_dict) 44 job_id = d.pop("jobId") 45 46 accepted_job = cls( 47 job_id=job_id, 48 ) 49 50 accepted_job.additional_properties = d 51 return accepted_job 52 53 @property 54 def additional_keys(self) -> list[str]: 55 return list(self.additional_properties.keys()) 56 57 def __getitem__(self, key: str) -> Any: 58 return self.additional_properties[key] 59 60 def __setitem__(self, key: str, value: Any) -> None: 61 self.additional_properties[key] = value 62 63 def __delitem__(self, key: str) -> None: 64 del self.additional_properties[key] 65 66 def __contains__(self, key: str) -> bool: 67 return key in self.additional_properties
Response returned by async endpoints (202 Accepted). The jobId is deterministic for the
same input parameters — repeated calls with identical params return the same id.
Example:
{'jobId': '13RBLGQlPnfDjO6wyKSX8i'}
Attributes:
job_id (str): Unique job identifier; use this to poll for completion. Example: 13RBLGQlPnfDjO6wyKSX8i.
24def __init__(self, job_id): 25 self.job_id = job_id 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class AcceptedJob.
15@_attrs_define 16class AuthTokenError: 17 """Error envelope returned by `POST /auth/token` when the API key is rejected. 18 19 Attributes: 20 code (AuthTokenErrorCode): Machine-readable error reason. 21 message (str): Human-readable description of the failure. 22 """ 23 24 code: AuthTokenErrorCode 25 message: str 26 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 27 28 def to_dict(self) -> dict[str, Any]: 29 code = self.code.value 30 31 message = self.message 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "code": code, 38 "message": message, 39 } 40 ) 41 42 return field_dict 43 44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 code = AuthTokenErrorCode(d.pop("code")) 48 49 message = d.pop("message") 50 51 auth_token_error = cls( 52 code=code, 53 message=message, 54 ) 55 56 auth_token_error.additional_properties = d 57 return auth_token_error 58 59 @property 60 def additional_keys(self) -> list[str]: 61 return list(self.additional_properties.keys()) 62 63 def __getitem__(self, key: str) -> Any: 64 return self.additional_properties[key] 65 66 def __setitem__(self, key: str, value: Any) -> None: 67 self.additional_properties[key] = value 68 69 def __delitem__(self, key: str) -> None: 70 del self.additional_properties[key] 71 72 def __contains__(self, key: str) -> bool: 73 return key in self.additional_properties
Error envelope returned by POST /auth/token when the API key is rejected.
Attributes: code (AuthTokenErrorCode): Machine-readable error reason. message (str): Human-readable description of the failure.
25def __init__(self, code, message): 26 self.code = code 27 self.message = message 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class AuthTokenError.
44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 code = AuthTokenErrorCode(d.pop("code")) 48 49 message = d.pop("message") 50 51 auth_token_error = cls( 52 code=code, 53 message=message, 54 ) 55 56 auth_token_error.additional_properties = d 57 return auth_token_error
5class AuthTokenErrorCode(str, Enum): 6 APIKEY_EXPIRED = "apikey_expired" 7 APIKEY_REVOKED = "apikey_revoked" 8 INVALID_APIKEY = "invalid_apikey" 9 10 def __str__(self) -> str: 11 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class AuthTokenResponse: 19 """ 20 Attributes: 21 access_token (str): Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints. 22 token_type (AuthTokenResponseTokenType): Always `Bearer`. 23 expires_in (int): Seconds until the JWT expires (typically 3600). Example: 3600. 24 tier (AuthTokenResponseTier): Subscription tier this token was issued for. Drives rate limits and feature flags 25 on downstream endpoints. Example: free. 26 scopes (list[str] | Unset): Scopes granted to this token. Reserved for future use; currently always empty. 27 """ 28 29 access_token: str 30 token_type: AuthTokenResponseTokenType 31 expires_in: int 32 tier: AuthTokenResponseTier 33 scopes: list[str] | Unset = UNSET 34 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 35 36 def to_dict(self) -> dict[str, Any]: 37 access_token = self.access_token 38 39 token_type = self.token_type.value 40 41 expires_in = self.expires_in 42 43 tier = self.tier.value 44 45 scopes: list[str] | Unset = UNSET 46 if not isinstance(self.scopes, Unset): 47 scopes = self.scopes 48 49 field_dict: dict[str, Any] = {} 50 field_dict.update(self.additional_properties) 51 field_dict.update( 52 { 53 "access_token": access_token, 54 "token_type": token_type, 55 "expires_in": expires_in, 56 "tier": tier, 57 } 58 ) 59 if scopes is not UNSET: 60 field_dict["scopes"] = scopes 61 62 return field_dict 63 64 @classmethod 65 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 66 d = dict(src_dict) 67 access_token = d.pop("access_token") 68 69 token_type = AuthTokenResponseTokenType(d.pop("token_type")) 70 71 expires_in = d.pop("expires_in") 72 73 tier = AuthTokenResponseTier(d.pop("tier")) 74 75 scopes = cast(list[str], d.pop("scopes", UNSET)) 76 77 auth_token_response = cls( 78 access_token=access_token, 79 token_type=token_type, 80 expires_in=expires_in, 81 tier=tier, 82 scopes=scopes, 83 ) 84 85 auth_token_response.additional_properties = d 86 return auth_token_response 87 88 @property 89 def additional_keys(self) -> list[str]: 90 return list(self.additional_properties.keys()) 91 92 def __getitem__(self, key: str) -> Any: 93 return self.additional_properties[key] 94 95 def __setitem__(self, key: str, value: Any) -> None: 96 self.additional_properties[key] = value 97 98 def __delitem__(self, key: str) -> None: 99 del self.additional_properties[key] 100 101 def __contains__(self, key: str) -> bool: 102 return key in self.additional_properties
Attributes:
access_token (str): Short-lived HS256 JWT. Send as Authorization: Bearer <token> on all other endpoints.
token_type (AuthTokenResponseTokenType): Always Bearer.
expires_in (int): Seconds until the JWT expires (typically 3600). Example: 3600.
tier (AuthTokenResponseTier): Subscription tier this token was issued for. Drives rate limits and feature flags
on downstream endpoints. Example: free.
scopes (list[str] | Unset): Scopes granted to this token. Reserved for future use; currently always empty.
28def __init__(self, access_token, token_type, expires_in, tier, scopes=attr_dict['scopes'].default): 29 self.access_token = access_token 30 self.token_type = token_type 31 self.expires_in = expires_in 32 self.tier = tier 33 self.scopes = scopes 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class AuthTokenResponse.
36 def to_dict(self) -> dict[str, Any]: 37 access_token = self.access_token 38 39 token_type = self.token_type.value 40 41 expires_in = self.expires_in 42 43 tier = self.tier.value 44 45 scopes: list[str] | Unset = UNSET 46 if not isinstance(self.scopes, Unset): 47 scopes = self.scopes 48 49 field_dict: dict[str, Any] = {} 50 field_dict.update(self.additional_properties) 51 field_dict.update( 52 { 53 "access_token": access_token, 54 "token_type": token_type, 55 "expires_in": expires_in, 56 "tier": tier, 57 } 58 ) 59 if scopes is not UNSET: 60 field_dict["scopes"] = scopes 61 62 return field_dict
64 @classmethod 65 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 66 d = dict(src_dict) 67 access_token = d.pop("access_token") 68 69 token_type = AuthTokenResponseTokenType(d.pop("token_type")) 70 71 expires_in = d.pop("expires_in") 72 73 tier = AuthTokenResponseTier(d.pop("tier")) 74 75 scopes = cast(list[str], d.pop("scopes", UNSET)) 76 77 auth_token_response = cls( 78 access_token=access_token, 79 token_type=token_type, 80 expires_in=expires_in, 81 tier=tier, 82 scopes=scopes, 83 ) 84 85 auth_token_response.additional_properties = d 86 return auth_token_response
5class AuthTokenResponseTier(str, Enum): 6 BASIC = "basic" 7 ELITE = "elite" 8 FREE = "free" 9 PRO = "pro" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class AuthTokenResponseTokenType(str, Enum): 6 BEARER = "Bearer" 7 8 def __str__(self) -> str: 9 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
18@_attrs_define 19class BacktestJobResult: 20 """Backtest job result. 21 22 Attributes: 23 results (ResultMap): Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). 24 Yield metrics (pnlTotal, pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy 25 emitted at least one trade. When signal storage is enabled, includes signal fields described below. `notices` 26 carries what the run had to say about itself, and is absent when it had nothing. 27 state (JobState): Information about a single job 28 """ 29 30 results: ResultMap 31 state: JobState 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 results = self.results.to_dict() 36 37 state = self.state.to_dict() 38 39 field_dict: dict[str, Any] = {} 40 field_dict.update(self.additional_properties) 41 field_dict.update( 42 { 43 "results": results, 44 "state": state, 45 } 46 ) 47 48 return field_dict 49 50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 from ..models.job_state import JobState 53 from ..models.result_map import ResultMap 54 55 d = dict(src_dict) 56 results = ResultMap.from_dict(d.pop("results")) 57 58 state = JobState.from_dict(d.pop("state")) 59 60 backtest_job_result = cls( 61 results=results, 62 state=state, 63 ) 64 65 backtest_job_result.additional_properties = d 66 return backtest_job_result 67 68 @property 69 def additional_keys(self) -> list[str]: 70 return list(self.additional_properties.keys()) 71 72 def __getitem__(self, key: str) -> Any: 73 return self.additional_properties[key] 74 75 def __setitem__(self, key: str, value: Any) -> None: 76 self.additional_properties[key] = value 77 78 def __delitem__(self, key: str) -> None: 79 del self.additional_properties[key] 80 81 def __contains__(self, key: str) -> bool: 82 return key in self.additional_properties
Backtest job result.
Attributes:
results (ResultMap): Execution result map. Always includes core fields (hostName, iops, strategyId, instrument).
Yield metrics (pnlTotal, pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy
emitted at least one trade. When signal storage is enabled, includes signal fields described below. notices
carries what the run had to say about itself, and is absent when it had nothing.
state (JobState): Information about a single job
25def __init__(self, results, state): 26 self.results = results 27 self.state = state 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class BacktestJobResult.
34 def to_dict(self) -> dict[str, Any]: 35 results = self.results.to_dict() 36 37 state = self.state.to_dict() 38 39 field_dict: dict[str, Any] = {} 40 field_dict.update(self.additional_properties) 41 field_dict.update( 42 { 43 "results": results, 44 "state": state, 45 } 46 ) 47 48 return field_dict
50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 from ..models.job_state import JobState 53 from ..models.result_map import ResultMap 54 55 d = dict(src_dict) 56 results = ResultMap.from_dict(d.pop("results")) 57 58 state = JobState.from_dict(d.pop("state")) 59 60 backtest_job_result = cls( 61 results=results, 62 state=state, 63 ) 64 65 backtest_job_result.additional_properties = d 66 return backtest_job_result
16@_attrs_define 17class CancelBacktestResponse200: 18 """ 19 Attributes: 20 status (CancelBacktestResponse200Status | Unset): Example: cancelling. 21 job_id (str | Unset): Example: 13RBLGQlPnfDjO6wyKSX8i. 22 """ 23 24 status: CancelBacktestResponse200Status | Unset = UNSET 25 job_id: str | Unset = UNSET 26 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 27 28 def to_dict(self) -> dict[str, Any]: 29 status: str | Unset = UNSET 30 if not isinstance(self.status, Unset): 31 status = self.status.value 32 33 job_id = self.job_id 34 35 field_dict: dict[str, Any] = {} 36 field_dict.update(self.additional_properties) 37 field_dict.update({}) 38 if status is not UNSET: 39 field_dict["status"] = status 40 if job_id is not UNSET: 41 field_dict["jobId"] = job_id 42 43 return field_dict 44 45 @classmethod 46 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 47 d = dict(src_dict) 48 _status = d.pop("status", UNSET) 49 status: CancelBacktestResponse200Status | Unset 50 if isinstance(_status, Unset): 51 status = UNSET 52 else: 53 status = CancelBacktestResponse200Status(_status) 54 55 job_id = d.pop("jobId", UNSET) 56 57 cancel_backtest_response_200 = cls( 58 status=status, 59 job_id=job_id, 60 ) 61 62 cancel_backtest_response_200.additional_properties = d 63 return cancel_backtest_response_200 64 65 @property 66 def additional_keys(self) -> list[str]: 67 return list(self.additional_properties.keys()) 68 69 def __getitem__(self, key: str) -> Any: 70 return self.additional_properties[key] 71 72 def __setitem__(self, key: str, value: Any) -> None: 73 self.additional_properties[key] = value 74 75 def __delitem__(self, key: str) -> None: 76 del self.additional_properties[key] 77 78 def __contains__(self, key: str) -> bool: 79 return key in self.additional_properties
Attributes: status (CancelBacktestResponse200Status | Unset): Example: cancelling. job_id (str | Unset): Example: 13RBLGQlPnfDjO6wyKSX8i.
25def __init__(self, status=attr_dict['status'].default, job_id=attr_dict['job_id'].default): 26 self.status = status 27 self.job_id = job_id 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class CancelBacktestResponse200.
28 def to_dict(self) -> dict[str, Any]: 29 status: str | Unset = UNSET 30 if not isinstance(self.status, Unset): 31 status = self.status.value 32 33 job_id = self.job_id 34 35 field_dict: dict[str, Any] = {} 36 field_dict.update(self.additional_properties) 37 field_dict.update({}) 38 if status is not UNSET: 39 field_dict["status"] = status 40 if job_id is not UNSET: 41 field_dict["jobId"] = job_id 42 43 return field_dict
45 @classmethod 46 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 47 d = dict(src_dict) 48 _status = d.pop("status", UNSET) 49 status: CancelBacktestResponse200Status | Unset 50 if isinstance(_status, Unset): 51 status = UNSET 52 else: 53 status = CancelBacktestResponse200Status(_status) 54 55 job_id = d.pop("jobId", UNSET) 56 57 cancel_backtest_response_200 = cls( 58 status=status, 59 job_id=job_id, 60 ) 61 62 cancel_backtest_response_200.additional_properties = d 63 return cancel_backtest_response_200
5class CancelBacktestResponse200Status(str, Enum): 6 CANCELLING = "cancelling" 7 8 def __str__(self) -> str: 9 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
15@_attrs_define 16class CancelSweepResponse200: 17 """ 18 Attributes: 19 status (CancelSweepResponse200Status): 20 sweep_id (str): 21 """ 22 23 status: CancelSweepResponse200Status 24 sweep_id: str 25 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 26 27 def to_dict(self) -> dict[str, Any]: 28 status = self.status.value 29 30 sweep_id = self.sweep_id 31 32 field_dict: dict[str, Any] = {} 33 field_dict.update(self.additional_properties) 34 field_dict.update( 35 { 36 "status": status, 37 "sweepId": sweep_id, 38 } 39 ) 40 41 return field_dict 42 43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 d = dict(src_dict) 46 status = CancelSweepResponse200Status(d.pop("status")) 47 48 sweep_id = d.pop("sweepId") 49 50 cancel_sweep_response_200 = cls( 51 status=status, 52 sweep_id=sweep_id, 53 ) 54 55 cancel_sweep_response_200.additional_properties = d 56 return cancel_sweep_response_200 57 58 @property 59 def additional_keys(self) -> list[str]: 60 return list(self.additional_properties.keys()) 61 62 def __getitem__(self, key: str) -> Any: 63 return self.additional_properties[key] 64 65 def __setitem__(self, key: str, value: Any) -> None: 66 self.additional_properties[key] = value 67 68 def __delitem__(self, key: str) -> None: 69 del self.additional_properties[key] 70 71 def __contains__(self, key: str) -> bool: 72 return key in self.additional_properties
Attributes: status (CancelSweepResponse200Status): sweep_id (str):
25def __init__(self, status, sweep_id): 26 self.status = status 27 self.sweep_id = sweep_id 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class CancelSweepResponse200.
43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 d = dict(src_dict) 46 status = CancelSweepResponse200Status(d.pop("status")) 47 48 sweep_id = d.pop("sweepId") 49 50 cancel_sweep_response_200 = cls( 51 status=status, 52 sweep_id=sweep_id, 53 ) 54 55 cancel_sweep_response_200.additional_properties = d 56 return cancel_sweep_response_200
5class CancelSweepResponse200Status(str, Enum): 6 CANCELLING = "cancelling" 7 8 def __str__(self) -> str: 9 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
19@_attrs_define 20class CompileStrategyResponse200: 21 """ 22 Attributes: 23 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 24 always yields the same id, for every caller, whatever its formatting. See 25 `POST /strategy` for exactly which rewrites preserve it and which do not. 26 Example: 6bsh31ikwkuivhtgcoa6s4. 27 declared_properties (list[DeclaredProperty] | Unset): What could be established about this strategy's sweep-key 28 vocabulary without 29 constructing it. See `DeclaredProperty` — best-effort, not exhaustive. 30 """ 31 32 strategy_id: str 33 declared_properties: list[DeclaredProperty] | Unset = UNSET 34 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 35 36 def to_dict(self) -> dict[str, Any]: 37 strategy_id = self.strategy_id 38 39 declared_properties: list[dict[str, Any]] | Unset = UNSET 40 if not isinstance(self.declared_properties, Unset): 41 declared_properties = [] 42 for declared_properties_item_data in self.declared_properties: 43 declared_properties_item = declared_properties_item_data.to_dict() 44 declared_properties.append(declared_properties_item) 45 46 field_dict: dict[str, Any] = {} 47 field_dict.update(self.additional_properties) 48 field_dict.update( 49 { 50 "strategyId": strategy_id, 51 } 52 ) 53 if declared_properties is not UNSET: 54 field_dict["declaredProperties"] = declared_properties 55 56 return field_dict 57 58 @classmethod 59 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 60 from ..models.declared_property import DeclaredProperty 61 62 d = dict(src_dict) 63 strategy_id = d.pop("strategyId") 64 65 _declared_properties = d.pop("declaredProperties", UNSET) 66 declared_properties: list[DeclaredProperty] | Unset = UNSET 67 if _declared_properties is not UNSET: 68 declared_properties = [] 69 for declared_properties_item_data in _declared_properties: 70 declared_properties_item = DeclaredProperty.from_dict(declared_properties_item_data) 71 72 declared_properties.append(declared_properties_item) 73 74 compile_strategy_response_200 = cls( 75 strategy_id=strategy_id, 76 declared_properties=declared_properties, 77 ) 78 79 compile_strategy_response_200.additional_properties = d 80 return compile_strategy_response_200 81 82 @property 83 def additional_keys(self) -> list[str]: 84 return list(self.additional_properties.keys()) 85 86 def __getitem__(self, key: str) -> Any: 87 return self.additional_properties[key] 88 89 def __setitem__(self, key: str, value: Any) -> None: 90 self.additional_properties[key] = value 91 92 def __delitem__(self, key: str) -> None: 93 del self.additional_properties[key] 94 95 def __contains__(self, key: str) -> bool: 96 return key in self.additional_properties
Attributes:
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
POST /strategy for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
declared_properties (list[DeclaredProperty] | Unset): What could be established about this strategy's sweep-key
vocabulary without
constructing it. See DeclaredProperty — best-effort, not exhaustive.
25def __init__(self, strategy_id, declared_properties=attr_dict['declared_properties'].default): 26 self.strategy_id = strategy_id 27 self.declared_properties = declared_properties 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class CompileStrategyResponse200.
36 def to_dict(self) -> dict[str, Any]: 37 strategy_id = self.strategy_id 38 39 declared_properties: list[dict[str, Any]] | Unset = UNSET 40 if not isinstance(self.declared_properties, Unset): 41 declared_properties = [] 42 for declared_properties_item_data in self.declared_properties: 43 declared_properties_item = declared_properties_item_data.to_dict() 44 declared_properties.append(declared_properties_item) 45 46 field_dict: dict[str, Any] = {} 47 field_dict.update(self.additional_properties) 48 field_dict.update( 49 { 50 "strategyId": strategy_id, 51 } 52 ) 53 if declared_properties is not UNSET: 54 field_dict["declaredProperties"] = declared_properties 55 56 return field_dict
58 @classmethod 59 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 60 from ..models.declared_property import DeclaredProperty 61 62 d = dict(src_dict) 63 strategy_id = d.pop("strategyId") 64 65 _declared_properties = d.pop("declaredProperties", UNSET) 66 declared_properties: list[DeclaredProperty] | Unset = UNSET 67 if _declared_properties is not UNSET: 68 declared_properties = [] 69 for declared_properties_item_data in _declared_properties: 70 declared_properties_item = DeclaredProperty.from_dict(declared_properties_item_data) 71 72 declared_properties.append(declared_properties_item) 73 74 compile_strategy_response_200 = cls( 75 strategy_id=strategy_id, 76 declared_properties=declared_properties, 77 ) 78 79 compile_strategy_response_200.additional_properties = d 80 return compile_strategy_response_200
17@_attrs_define 18class CoverageWindow: 19 """The time range of available data for a single data type 20 21 Attributes: 22 from_ (datetime.datetime | Unset): Earliest timestamp with data available Example: 2026-04-10T21:00:00Z. 23 to (datetime.datetime | Unset): Latest timestamp with data available Example: 2026-07-09T20:31:08Z. 24 inactive_since (datetime.datetime | Unset): If the instrument stopped producing this data type 25 (delisted/inactive), the timestamp it went inactive. Optional — omitted while the instrument is active. Example: 26 2026-06-30T12:00:00Z. 27 """ 28 29 from_: datetime.datetime | Unset = UNSET 30 to: datetime.datetime | Unset = UNSET 31 inactive_since: datetime.datetime | Unset = UNSET 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 from_: str | Unset = UNSET 36 if not isinstance(self.from_, Unset): 37 from_ = self.from_.isoformat() 38 39 to: str | Unset = UNSET 40 if not isinstance(self.to, Unset): 41 to = self.to.isoformat() 42 43 inactive_since: str | Unset = UNSET 44 if not isinstance(self.inactive_since, Unset): 45 inactive_since = self.inactive_since.isoformat() 46 47 field_dict: dict[str, Any] = {} 48 field_dict.update(self.additional_properties) 49 field_dict.update({}) 50 if from_ is not UNSET: 51 field_dict["from"] = from_ 52 if to is not UNSET: 53 field_dict["to"] = to 54 if inactive_since is not UNSET: 55 field_dict["inactiveSince"] = inactive_since 56 57 return field_dict 58 59 @classmethod 60 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 61 d = dict(src_dict) 62 _from_ = d.pop("from", UNSET) 63 from_: datetime.datetime | Unset 64 if isinstance(_from_, Unset): 65 from_ = UNSET 66 else: 67 from_ = isoparse(_from_) 68 69 _to = d.pop("to", UNSET) 70 to: datetime.datetime | Unset 71 if isinstance(_to, Unset): 72 to = UNSET 73 else: 74 to = isoparse(_to) 75 76 _inactive_since = d.pop("inactiveSince", UNSET) 77 inactive_since: datetime.datetime | Unset 78 if isinstance(_inactive_since, Unset): 79 inactive_since = UNSET 80 else: 81 inactive_since = isoparse(_inactive_since) 82 83 coverage_window = cls( 84 from_=from_, 85 to=to, 86 inactive_since=inactive_since, 87 ) 88 89 coverage_window.additional_properties = d 90 return coverage_window 91 92 @property 93 def additional_keys(self) -> list[str]: 94 return list(self.additional_properties.keys()) 95 96 def __getitem__(self, key: str) -> Any: 97 return self.additional_properties[key] 98 99 def __setitem__(self, key: str, value: Any) -> None: 100 self.additional_properties[key] = value 101 102 def __delitem__(self, key: str) -> None: 103 del self.additional_properties[key] 104 105 def __contains__(self, key: str) -> bool: 106 return key in self.additional_properties
The time range of available data for a single data type
Attributes: from_ (datetime.datetime | Unset): Earliest timestamp with data available Example: 2026-04-10T21:00:00Z. to (datetime.datetime | Unset): Latest timestamp with data available Example: 2026-07-09T20:31:08Z. inactive_since (datetime.datetime | Unset): If the instrument stopped producing this data type (delisted/inactive), the timestamp it went inactive. Optional — omitted while the instrument is active. Example: 2026-06-30T12:00:00Z.
26def __init__(self, from_=attr_dict['from_'].default, to=attr_dict['to'].default, inactive_since=attr_dict['inactive_since'].default): 27 self.from_ = from_ 28 self.to = to 29 self.inactive_since = inactive_since 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class CoverageWindow.
34 def to_dict(self) -> dict[str, Any]: 35 from_: str | Unset = UNSET 36 if not isinstance(self.from_, Unset): 37 from_ = self.from_.isoformat() 38 39 to: str | Unset = UNSET 40 if not isinstance(self.to, Unset): 41 to = self.to.isoformat() 42 43 inactive_since: str | Unset = UNSET 44 if not isinstance(self.inactive_since, Unset): 45 inactive_since = self.inactive_since.isoformat() 46 47 field_dict: dict[str, Any] = {} 48 field_dict.update(self.additional_properties) 49 field_dict.update({}) 50 if from_ is not UNSET: 51 field_dict["from"] = from_ 52 if to is not UNSET: 53 field_dict["to"] = to 54 if inactive_since is not UNSET: 55 field_dict["inactiveSince"] = inactive_since 56 57 return field_dict
59 @classmethod 60 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 61 d = dict(src_dict) 62 _from_ = d.pop("from", UNSET) 63 from_: datetime.datetime | Unset 64 if isinstance(_from_, Unset): 65 from_ = UNSET 66 else: 67 from_ = isoparse(_from_) 68 69 _to = d.pop("to", UNSET) 70 to: datetime.datetime | Unset 71 if isinstance(_to, Unset): 72 to = UNSET 73 else: 74 to = isoparse(_to) 75 76 _inactive_since = d.pop("inactiveSince", UNSET) 77 inactive_since: datetime.datetime | Unset 78 if isinstance(_inactive_since, Unset): 79 inactive_since = UNSET 80 else: 81 inactive_since = isoparse(_inactive_since) 82 83 coverage_window = cls( 84 from_=from_, 85 to=to, 86 inactive_since=inactive_since, 87 ) 88 89 coverage_window.additional_properties = d 90 return coverage_window
13@_attrs_define 14class CreateDatasetBody: 15 """ 16 Attributes: 17 name (str): A name unique among your datasets. `409` if already taken. Example: My BTC ticks. 18 instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT. 19 """ 20 21 name: str 22 instrument: str 23 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 24 25 def to_dict(self) -> dict[str, Any]: 26 name = self.name 27 28 instrument = self.instrument 29 30 field_dict: dict[str, Any] = {} 31 field_dict.update(self.additional_properties) 32 field_dict.update( 33 { 34 "name": name, 35 "instrument": instrument, 36 } 37 ) 38 39 return field_dict 40 41 @classmethod 42 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 43 d = dict(src_dict) 44 name = d.pop("name") 45 46 instrument = d.pop("instrument") 47 48 create_dataset_body = cls( 49 name=name, 50 instrument=instrument, 51 ) 52 53 create_dataset_body.additional_properties = d 54 return create_dataset_body 55 56 @property 57 def additional_keys(self) -> list[str]: 58 return list(self.additional_properties.keys()) 59 60 def __getitem__(self, key: str) -> Any: 61 return self.additional_properties[key] 62 63 def __setitem__(self, key: str, value: Any) -> None: 64 self.additional_properties[key] = value 65 66 def __delitem__(self, key: str) -> None: 67 del self.additional_properties[key] 68 69 def __contains__(self, key: str) -> bool: 70 return key in self.additional_properties
Attributes:
name (str): A name unique among your datasets. 409 if already taken. Example: My BTC ticks.
instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
25def __init__(self, name, instrument): 26 self.name = name 27 self.instrument = instrument 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class CreateDatasetBody.
41 @classmethod 42 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 43 d = dict(src_dict) 44 name = d.pop("name") 45 46 instrument = d.pop("instrument") 47 48 create_dataset_body = cls( 49 name=name, 50 instrument=instrument, 51 ) 52 53 create_dataset_body.additional_properties = d 54 return create_dataset_body
18@_attrs_define 19class Dataset: 20 """A dataset's own metadata — not its data. `currentVersionId` is what a prepare against 21 `exchangeId: user` reads by default; see `DatasetVersion` for what a version carries. 22 23 `from`/`to`/`cadence` mirror that current version's own discovered range and cadence, so 24 you don't need a second call to `GET /datasets/{datasetId}/uploads/{uploadId}` just to see 25 what a dataset covers. Absent until a version exists. 26 27 Attributes: 28 dataset_id (str): Opaque id, returned by `POST /datasets`. Example: ds_3f9a1c2e7b0d4a5f. 29 name (str): Unique among your datasets. Example: My BTC ticks. 30 type_ (DatasetType): Always `ticker` in v1. Example: ticker. 31 instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT. 32 created_at (datetime.datetime): When the dataset was created. Example: 2026-08-20T09:00:00Z. 33 current_version_id (str | Unset): The id of the most recently finalized, successfully ingested version. Absent 34 until at 35 least one upload has finished ingesting. 36 Example: dsv_8e2b4f19c6a03d7e. 37 updated_at (datetime.datetime | Unset): When `currentVersionId` last changed. Absent until it has a value. 38 Example: 2026-08-20T09:04:12Z. 39 from_ (datetime.datetime | Unset): Start of `currentVersionId`'s own data range, as discovered at ingest time. 40 Absent 41 until a version exists. 42 Example: 2026-03-01T00:00:00Z. 43 to (datetime.datetime | Unset): End of `currentVersionId`'s own data range, as discovered at ingest time. Absent 44 until 45 a version exists. 46 Example: 2026-03-08T00:00:00Z. 47 cadence (str | Unset): `currentVersionId`'s own discovered bar cadence (e.g. `1s`, `1m`, `1h`). Absent until a 48 version exists. 49 Example: 1m. 50 """ 51 52 dataset_id: str 53 name: str 54 type_: DatasetType 55 instrument: str 56 created_at: datetime.datetime 57 current_version_id: str | Unset = UNSET 58 updated_at: datetime.datetime | Unset = UNSET 59 from_: datetime.datetime | Unset = UNSET 60 to: datetime.datetime | Unset = UNSET 61 cadence: str | Unset = UNSET 62 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 63 64 def to_dict(self) -> dict[str, Any]: 65 dataset_id = self.dataset_id 66 67 name = self.name 68 69 type_ = self.type_.value 70 71 instrument = self.instrument 72 73 created_at = self.created_at.isoformat() 74 75 current_version_id = self.current_version_id 76 77 updated_at: str | Unset = UNSET 78 if not isinstance(self.updated_at, Unset): 79 updated_at = self.updated_at.isoformat() 80 81 from_: str | Unset = UNSET 82 if not isinstance(self.from_, Unset): 83 from_ = self.from_.isoformat() 84 85 to: str | Unset = UNSET 86 if not isinstance(self.to, Unset): 87 to = self.to.isoformat() 88 89 cadence = self.cadence 90 91 field_dict: dict[str, Any] = {} 92 field_dict.update(self.additional_properties) 93 field_dict.update( 94 { 95 "datasetId": dataset_id, 96 "name": name, 97 "type": type_, 98 "instrument": instrument, 99 "createdAt": created_at, 100 } 101 ) 102 if current_version_id is not UNSET: 103 field_dict["currentVersionId"] = current_version_id 104 if updated_at is not UNSET: 105 field_dict["updatedAt"] = updated_at 106 if from_ is not UNSET: 107 field_dict["from"] = from_ 108 if to is not UNSET: 109 field_dict["to"] = to 110 if cadence is not UNSET: 111 field_dict["cadence"] = cadence 112 113 return field_dict 114 115 @classmethod 116 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 117 d = dict(src_dict) 118 dataset_id = d.pop("datasetId") 119 120 name = d.pop("name") 121 122 type_ = DatasetType(d.pop("type")) 123 124 instrument = d.pop("instrument") 125 126 created_at = isoparse(d.pop("createdAt")) 127 128 current_version_id = d.pop("currentVersionId", UNSET) 129 130 _updated_at = d.pop("updatedAt", UNSET) 131 updated_at: datetime.datetime | Unset 132 if isinstance(_updated_at, Unset): 133 updated_at = UNSET 134 else: 135 updated_at = isoparse(_updated_at) 136 137 _from_ = d.pop("from", UNSET) 138 from_: datetime.datetime | Unset 139 if isinstance(_from_, Unset): 140 from_ = UNSET 141 else: 142 from_ = isoparse(_from_) 143 144 _to = d.pop("to", UNSET) 145 to: datetime.datetime | Unset 146 if isinstance(_to, Unset): 147 to = UNSET 148 else: 149 to = isoparse(_to) 150 151 cadence = d.pop("cadence", UNSET) 152 153 dataset = cls( 154 dataset_id=dataset_id, 155 name=name, 156 type_=type_, 157 instrument=instrument, 158 created_at=created_at, 159 current_version_id=current_version_id, 160 updated_at=updated_at, 161 from_=from_, 162 to=to, 163 cadence=cadence, 164 ) 165 166 dataset.additional_properties = d 167 return dataset 168 169 @property 170 def additional_keys(self) -> list[str]: 171 return list(self.additional_properties.keys()) 172 173 def __getitem__(self, key: str) -> Any: 174 return self.additional_properties[key] 175 176 def __setitem__(self, key: str, value: Any) -> None: 177 self.additional_properties[key] = value 178 179 def __delitem__(self, key: str) -> None: 180 del self.additional_properties[key] 181 182 def __contains__(self, key: str) -> bool: 183 return key in self.additional_properties
A dataset's own metadata — not its data. currentVersionId is what a prepare against
exchangeId: user reads by default; see DatasetVersion for what a version carries.
from/to/cadence mirror that current version's own discovered range and cadence, so
you don't need a second call to GET /datasets/{datasetId}/uploads/{uploadId} just to see
what a dataset covers. Absent until a version exists.
Attributes:
dataset_id (str): Opaque id, returned by `POST /datasets`. Example: ds_3f9a1c2e7b0d4a5f.
name (str): Unique among your datasets. Example: My BTC ticks.
type_ (DatasetType): Always `ticker` in v1. Example: ticker.
instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
created_at (datetime.datetime): When the dataset was created. Example: 2026-08-20T09:00:00Z.
current_version_id (str | Unset): The id of the most recently finalized, successfully ingested version. Absent
until at
least one upload has finished ingesting.
Example: dsv_8e2b4f19c6a03d7e.
updated_at (datetime.datetime | Unset): When `currentVersionId` last changed. Absent until it has a value.
Example: 2026-08-20T09:04:12Z.
from_ (datetime.datetime | Unset): Start of `currentVersionId`'s own data range, as discovered at ingest time.
Absent
until a version exists.
Example: 2026-03-01T00:00:00Z.
to (datetime.datetime | Unset): End of `currentVersionId`'s own data range, as discovered at ingest time. Absent
until
a version exists.
Example: 2026-03-08T00:00:00Z.
cadence (str | Unset): `currentVersionId`'s own discovered bar cadence (e.g. `1s`, `1m`, `1h`). Absent until a
version exists.
Example: 1m.
33def __init__(self, dataset_id, name, type_, instrument, created_at, current_version_id=attr_dict['current_version_id'].default, updated_at=attr_dict['updated_at'].default, from_=attr_dict['from_'].default, to=attr_dict['to'].default, cadence=attr_dict['cadence'].default): 34 self.dataset_id = dataset_id 35 self.name = name 36 self.type_ = type_ 37 self.instrument = instrument 38 self.created_at = created_at 39 self.current_version_id = current_version_id 40 self.updated_at = updated_at 41 self.from_ = from_ 42 self.to = to 43 self.cadence = cadence 44 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class Dataset.
64 def to_dict(self) -> dict[str, Any]: 65 dataset_id = self.dataset_id 66 67 name = self.name 68 69 type_ = self.type_.value 70 71 instrument = self.instrument 72 73 created_at = self.created_at.isoformat() 74 75 current_version_id = self.current_version_id 76 77 updated_at: str | Unset = UNSET 78 if not isinstance(self.updated_at, Unset): 79 updated_at = self.updated_at.isoformat() 80 81 from_: str | Unset = UNSET 82 if not isinstance(self.from_, Unset): 83 from_ = self.from_.isoformat() 84 85 to: str | Unset = UNSET 86 if not isinstance(self.to, Unset): 87 to = self.to.isoformat() 88 89 cadence = self.cadence 90 91 field_dict: dict[str, Any] = {} 92 field_dict.update(self.additional_properties) 93 field_dict.update( 94 { 95 "datasetId": dataset_id, 96 "name": name, 97 "type": type_, 98 "instrument": instrument, 99 "createdAt": created_at, 100 } 101 ) 102 if current_version_id is not UNSET: 103 field_dict["currentVersionId"] = current_version_id 104 if updated_at is not UNSET: 105 field_dict["updatedAt"] = updated_at 106 if from_ is not UNSET: 107 field_dict["from"] = from_ 108 if to is not UNSET: 109 field_dict["to"] = to 110 if cadence is not UNSET: 111 field_dict["cadence"] = cadence 112 113 return field_dict
115 @classmethod 116 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 117 d = dict(src_dict) 118 dataset_id = d.pop("datasetId") 119 120 name = d.pop("name") 121 122 type_ = DatasetType(d.pop("type")) 123 124 instrument = d.pop("instrument") 125 126 created_at = isoparse(d.pop("createdAt")) 127 128 current_version_id = d.pop("currentVersionId", UNSET) 129 130 _updated_at = d.pop("updatedAt", UNSET) 131 updated_at: datetime.datetime | Unset 132 if isinstance(_updated_at, Unset): 133 updated_at = UNSET 134 else: 135 updated_at = isoparse(_updated_at) 136 137 _from_ = d.pop("from", UNSET) 138 from_: datetime.datetime | Unset 139 if isinstance(_from_, Unset): 140 from_ = UNSET 141 else: 142 from_ = isoparse(_from_) 143 144 _to = d.pop("to", UNSET) 145 to: datetime.datetime | Unset 146 if isinstance(_to, Unset): 147 to = UNSET 148 else: 149 to = isoparse(_to) 150 151 cadence = d.pop("cadence", UNSET) 152 153 dataset = cls( 154 dataset_id=dataset_id, 155 name=name, 156 type_=type_, 157 instrument=instrument, 158 created_at=created_at, 159 current_version_id=current_version_id, 160 updated_at=updated_at, 161 from_=from_, 162 to=to, 163 cadence=cadence, 164 ) 165 166 dataset.additional_properties = d 167 return dataset
19@_attrs_define 20class DatasetCreated: 21 """The metadata available immediately after creating a dataset, plus its first upload 22 session — the presigned URL to PUT the file to. Version-derived fields such as 23 `createdAt`, `currentVersionId`, range, and cadence are available from `GET /datasets/{datasetId}` 24 after the relevant lifecycle stages, not in this creation response. 25 26 Attributes: 27 upload_id (str): Identifies this upload session. Pass to 28 `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes. 29 Example: up_1a2b3c4d5e6f7a8b. 30 upload (DatasetUploadTarget): A presigned destination for uploading a raw dataset file directly to storage. 31 dataset_id (str): Opaque id of the newly created dataset. Example: ds_3f9a1c2e7b0d4a5f. 32 name (str): Unique name of the newly created dataset. Example: My BTC ticks. 33 type_ (DatasetCreatedType): Always `ticker` in v1. Example: ticker. 34 instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT. 35 """ 36 37 upload_id: str 38 upload: DatasetUploadTarget 39 dataset_id: str 40 name: str 41 type_: DatasetCreatedType 42 instrument: str 43 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 44 45 def to_dict(self) -> dict[str, Any]: 46 upload_id = self.upload_id 47 48 upload = self.upload.to_dict() 49 50 dataset_id = self.dataset_id 51 52 name = self.name 53 54 type_ = self.type_.value 55 56 instrument = self.instrument 57 58 field_dict: dict[str, Any] = {} 59 field_dict.update(self.additional_properties) 60 field_dict.update( 61 { 62 "uploadId": upload_id, 63 "upload": upload, 64 "datasetId": dataset_id, 65 "name": name, 66 "type": type_, 67 "instrument": instrument, 68 } 69 ) 70 71 return field_dict 72 73 @classmethod 74 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 75 from ..models.dataset_upload_target import DatasetUploadTarget 76 77 d = dict(src_dict) 78 upload_id = d.pop("uploadId") 79 80 upload = DatasetUploadTarget.from_dict(d.pop("upload")) 81 82 dataset_id = d.pop("datasetId") 83 84 name = d.pop("name") 85 86 type_ = DatasetCreatedType(d.pop("type")) 87 88 instrument = d.pop("instrument") 89 90 dataset_created = cls( 91 upload_id=upload_id, 92 upload=upload, 93 dataset_id=dataset_id, 94 name=name, 95 type_=type_, 96 instrument=instrument, 97 ) 98 99 dataset_created.additional_properties = d 100 return dataset_created 101 102 @property 103 def additional_keys(self) -> list[str]: 104 return list(self.additional_properties.keys()) 105 106 def __getitem__(self, key: str) -> Any: 107 return self.additional_properties[key] 108 109 def __setitem__(self, key: str, value: Any) -> None: 110 self.additional_properties[key] = value 111 112 def __delitem__(self, key: str) -> None: 113 del self.additional_properties[key] 114 115 def __contains__(self, key: str) -> bool: 116 return key in self.additional_properties
The metadata available immediately after creating a dataset, plus its first upload
session — the presigned URL to PUT the file to. Version-derived fields such as
createdAt, currentVersionId, range, and cadence are available from GET /datasets/{datasetId}
after the relevant lifecycle stages, not in this creation response.
Attributes:
upload_id (str): Identifies this upload session. Pass to
`POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes.
Example: up_1a2b3c4d5e6f7a8b.
upload (DatasetUploadTarget): A presigned destination for uploading a raw dataset file directly to storage.
dataset_id (str): Opaque id of the newly created dataset. Example: ds_3f9a1c2e7b0d4a5f.
name (str): Unique name of the newly created dataset. Example: My BTC ticks.
type_ (DatasetCreatedType): Always `ticker` in v1. Example: ticker.
instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
29def __init__(self, upload_id, upload, dataset_id, name, type_, instrument): 30 self.upload_id = upload_id 31 self.upload = upload 32 self.dataset_id = dataset_id 33 self.name = name 34 self.type_ = type_ 35 self.instrument = instrument 36 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetCreated.
45 def to_dict(self) -> dict[str, Any]: 46 upload_id = self.upload_id 47 48 upload = self.upload.to_dict() 49 50 dataset_id = self.dataset_id 51 52 name = self.name 53 54 type_ = self.type_.value 55 56 instrument = self.instrument 57 58 field_dict: dict[str, Any] = {} 59 field_dict.update(self.additional_properties) 60 field_dict.update( 61 { 62 "uploadId": upload_id, 63 "upload": upload, 64 "datasetId": dataset_id, 65 "name": name, 66 "type": type_, 67 "instrument": instrument, 68 } 69 ) 70 71 return field_dict
73 @classmethod 74 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 75 from ..models.dataset_upload_target import DatasetUploadTarget 76 77 d = dict(src_dict) 78 upload_id = d.pop("uploadId") 79 80 upload = DatasetUploadTarget.from_dict(d.pop("upload")) 81 82 dataset_id = d.pop("datasetId") 83 84 name = d.pop("name") 85 86 type_ = DatasetCreatedType(d.pop("type")) 87 88 instrument = d.pop("instrument") 89 90 dataset_created = cls( 91 upload_id=upload_id, 92 upload=upload, 93 dataset_id=dataset_id, 94 name=name, 95 type_=type_, 96 instrument=instrument, 97 ) 98 99 dataset_created.additional_properties = d 100 return dataset_created
5class DatasetCreatedType(str, Enum): 6 TICKER = "ticker" 7 8 def __str__(self) -> str: 9 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class DatasetType(str, Enum): 6 TICKER = "ticker" 7 8 def __str__(self) -> str: 9 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class DatasetUploadSession: 19 """An upload session — an id plus the presigned URL to PUT the raw file to. Returned both by 20 `POST /datasets` (as part of the new dataset) and by `POST /datasets/{datasetId}/uploads` 21 (on its own, for an existing one). 22 23 Attributes: 24 upload_id (str): Identifies this upload session. Pass to 25 `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes. 26 Example: up_1a2b3c4d5e6f7a8b. 27 upload (DatasetUploadTarget): A presigned destination for uploading a raw dataset file directly to storage. 28 """ 29 30 upload_id: str 31 upload: DatasetUploadTarget 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 upload_id = self.upload_id 36 37 upload = self.upload.to_dict() 38 39 field_dict: dict[str, Any] = {} 40 field_dict.update(self.additional_properties) 41 field_dict.update( 42 { 43 "uploadId": upload_id, 44 "upload": upload, 45 } 46 ) 47 48 return field_dict 49 50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 from ..models.dataset_upload_target import DatasetUploadTarget 53 54 d = dict(src_dict) 55 upload_id = d.pop("uploadId") 56 57 upload = DatasetUploadTarget.from_dict(d.pop("upload")) 58 59 dataset_upload_session = cls( 60 upload_id=upload_id, 61 upload=upload, 62 ) 63 64 dataset_upload_session.additional_properties = d 65 return dataset_upload_session 66 67 @property 68 def additional_keys(self) -> list[str]: 69 return list(self.additional_properties.keys()) 70 71 def __getitem__(self, key: str) -> Any: 72 return self.additional_properties[key] 73 74 def __setitem__(self, key: str, value: Any) -> None: 75 self.additional_properties[key] = value 76 77 def __delitem__(self, key: str) -> None: 78 del self.additional_properties[key] 79 80 def __contains__(self, key: str) -> bool: 81 return key in self.additional_properties
An upload session — an id plus the presigned URL to PUT the raw file to. Returned both by
POST /datasets (as part of the new dataset) and by POST /datasets/{datasetId}/uploads
(on its own, for an existing one).
Attributes:
upload_id (str): Identifies this upload session. Pass to
`POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes.
Example: up_1a2b3c4d5e6f7a8b.
upload (DatasetUploadTarget): A presigned destination for uploading a raw dataset file directly to storage.
25def __init__(self, upload_id, upload): 26 self.upload_id = upload_id 27 self.upload = upload 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetUploadSession.
34 def to_dict(self) -> dict[str, Any]: 35 upload_id = self.upload_id 36 37 upload = self.upload.to_dict() 38 39 field_dict: dict[str, Any] = {} 40 field_dict.update(self.additional_properties) 41 field_dict.update( 42 { 43 "uploadId": upload_id, 44 "upload": upload, 45 } 46 ) 47 48 return field_dict
50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 from ..models.dataset_upload_target import DatasetUploadTarget 53 54 d = dict(src_dict) 55 upload_id = d.pop("uploadId") 56 57 upload = DatasetUploadTarget.from_dict(d.pop("upload")) 58 59 dataset_upload_session = cls( 60 upload_id=upload_id, 61 upload=upload, 62 ) 63 64 dataset_upload_session.additional_properties = d 65 return dataset_upload_session
20@_attrs_define 21class DatasetUploadState: 22 """Progress of one upload, from staged through ingest. Postgres-backed once a version exists, 23 so `ready`/`failed` are permanent answers; `uploading`/`ingesting` reflect in-flight state 24 that can itself age out — see the `404` case on `GET .../uploads/{uploadId}`. 25 26 Attributes: 27 upload_id (str): Example: up_1a2b3c4d5e6f7a8b. 28 status (DatasetUploadStateStatus): * `uploading` — the file was PUT to the presigned URL, but `finalize` has not 29 been 30 called yet. 31 * `ingesting` — `finalize` was called; the worker is parsing and validating the file. 32 * `ready` — ingested successfully. `version` carries the result. 33 * `failed` — ingest rejected the file (e.g. bad CSV contract, mixed timestamp units). 34 Example: ready. 35 job_id (str | Unset): The ingest job id, while `status` is `ingesting`. 36 version (DatasetVersion | Unset): One successfully ingested upload. Cadence and timestamp unit are discovered 37 from the file, 38 not declared by the caller. 39 """ 40 41 upload_id: str 42 status: DatasetUploadStateStatus 43 job_id: str | Unset = UNSET 44 version: DatasetVersion | Unset = UNSET 45 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 46 47 def to_dict(self) -> dict[str, Any]: 48 upload_id = self.upload_id 49 50 status = self.status.value 51 52 job_id = self.job_id 53 54 version: dict[str, Any] | Unset = UNSET 55 if not isinstance(self.version, Unset): 56 version = self.version.to_dict() 57 58 field_dict: dict[str, Any] = {} 59 field_dict.update(self.additional_properties) 60 field_dict.update( 61 { 62 "uploadId": upload_id, 63 "status": status, 64 } 65 ) 66 if job_id is not UNSET: 67 field_dict["jobId"] = job_id 68 if version is not UNSET: 69 field_dict["version"] = version 70 71 return field_dict 72 73 @classmethod 74 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 75 from ..models.dataset_version import DatasetVersion 76 77 d = dict(src_dict) 78 upload_id = d.pop("uploadId") 79 80 status = DatasetUploadStateStatus(d.pop("status")) 81 82 job_id = d.pop("jobId", UNSET) 83 84 _version = d.pop("version", UNSET) 85 version: DatasetVersion | Unset 86 if isinstance(_version, Unset): 87 version = UNSET 88 else: 89 version = DatasetVersion.from_dict(_version) 90 91 dataset_upload_state = cls( 92 upload_id=upload_id, 93 status=status, 94 job_id=job_id, 95 version=version, 96 ) 97 98 dataset_upload_state.additional_properties = d 99 return dataset_upload_state 100 101 @property 102 def additional_keys(self) -> list[str]: 103 return list(self.additional_properties.keys()) 104 105 def __getitem__(self, key: str) -> Any: 106 return self.additional_properties[key] 107 108 def __setitem__(self, key: str, value: Any) -> None: 109 self.additional_properties[key] = value 110 111 def __delitem__(self, key: str) -> None: 112 del self.additional_properties[key] 113 114 def __contains__(self, key: str) -> bool: 115 return key in self.additional_properties
Progress of one upload, from staged through ingest. Postgres-backed once a version exists,
so ready/failed are permanent answers; uploading/ingesting reflect in-flight state
that can itself age out — see the 404 case on GET .../uploads/{uploadId}.
Attributes:
upload_id (str): Example: up_1a2b3c4d5e6f7a8b.
status (DatasetUploadStateStatus): * `uploading` — the file was PUT to the presigned URL, but `finalize` has not
been
called yet.
* `ingesting` — `finalize` was called; the worker is parsing and validating the file.
* `ready` — ingested successfully. `version` carries the result.
* `failed` — ingest rejected the file (e.g. bad CSV contract, mixed timestamp units).
Example: ready.
job_id (str | Unset): The ingest job id, while `status` is `ingesting`.
version (DatasetVersion | Unset): One successfully ingested upload. Cadence and timestamp unit are discovered
from the file,
not declared by the caller.
27def __init__(self, upload_id, status, job_id=attr_dict['job_id'].default, version=attr_dict['version'].default): 28 self.upload_id = upload_id 29 self.status = status 30 self.job_id = job_id 31 self.version = version 32 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetUploadState.
47 def to_dict(self) -> dict[str, Any]: 48 upload_id = self.upload_id 49 50 status = self.status.value 51 52 job_id = self.job_id 53 54 version: dict[str, Any] | Unset = UNSET 55 if not isinstance(self.version, Unset): 56 version = self.version.to_dict() 57 58 field_dict: dict[str, Any] = {} 59 field_dict.update(self.additional_properties) 60 field_dict.update( 61 { 62 "uploadId": upload_id, 63 "status": status, 64 } 65 ) 66 if job_id is not UNSET: 67 field_dict["jobId"] = job_id 68 if version is not UNSET: 69 field_dict["version"] = version 70 71 return field_dict
73 @classmethod 74 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 75 from ..models.dataset_version import DatasetVersion 76 77 d = dict(src_dict) 78 upload_id = d.pop("uploadId") 79 80 status = DatasetUploadStateStatus(d.pop("status")) 81 82 job_id = d.pop("jobId", UNSET) 83 84 _version = d.pop("version", UNSET) 85 version: DatasetVersion | Unset 86 if isinstance(_version, Unset): 87 version = UNSET 88 else: 89 version = DatasetVersion.from_dict(_version) 90 91 dataset_upload_state = cls( 92 upload_id=upload_id, 93 status=status, 94 job_id=job_id, 95 version=version, 96 ) 97 98 dataset_upload_state.additional_properties = d 99 return dataset_upload_state
5class DatasetUploadStateStatus(str, Enum): 6 FAILED = "failed" 7 INGESTING = "ingesting" 8 READY = "ready" 9 UPLOADING = "uploading" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
13@_attrs_define 14class DatasetUploadTarget: 15 """A presigned destination for uploading a raw dataset file directly to storage. 16 17 Attributes: 18 url (str): Presigned URL. `PUT` the raw CSV file here directly — no `Authorization` header, 19 no other API credentials. 20 Example: https://storage.qtsurfer.com/uploads/00000000-.../up_1a2b3c4d5e6f7a8b/raw.csv?X-Amz-.... 21 expires_in_minutes (int): How long `url` stays valid. Example: 15. 22 """ 23 24 url: str 25 expires_in_minutes: int 26 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 27 28 def to_dict(self) -> dict[str, Any]: 29 url = self.url 30 31 expires_in_minutes = self.expires_in_minutes 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "url": url, 38 "expiresInMinutes": expires_in_minutes, 39 } 40 ) 41 42 return field_dict 43 44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 url = d.pop("url") 48 49 expires_in_minutes = d.pop("expiresInMinutes") 50 51 dataset_upload_target = cls( 52 url=url, 53 expires_in_minutes=expires_in_minutes, 54 ) 55 56 dataset_upload_target.additional_properties = d 57 return dataset_upload_target 58 59 @property 60 def additional_keys(self) -> list[str]: 61 return list(self.additional_properties.keys()) 62 63 def __getitem__(self, key: str) -> Any: 64 return self.additional_properties[key] 65 66 def __setitem__(self, key: str, value: Any) -> None: 67 self.additional_properties[key] = value 68 69 def __delitem__(self, key: str) -> None: 70 del self.additional_properties[key] 71 72 def __contains__(self, key: str) -> bool: 73 return key in self.additional_properties
A presigned destination for uploading a raw dataset file directly to storage.
Attributes:
url (str): Presigned URL. PUT the raw CSV file here directly — no Authorization header,
no other API credentials.
Example: https://storage.qtsurfer.com/uploads/00000000-.../up_1a2b3c4d5e6f7a8b/raw.csv?X-Amz-....
expires_in_minutes (int): How long url stays valid. Example: 15.
25def __init__(self, url, expires_in_minutes): 26 self.url = url 27 self.expires_in_minutes = expires_in_minutes 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetUploadTarget.
28 def to_dict(self) -> dict[str, Any]: 29 url = self.url 30 31 expires_in_minutes = self.expires_in_minutes 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "url": url, 38 "expiresInMinutes": expires_in_minutes, 39 } 40 ) 41 42 return field_dict
44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 url = d.pop("url") 48 49 expires_in_minutes = d.pop("expiresInMinutes") 50 51 dataset_upload_target = cls( 52 url=url, 53 expires_in_minutes=expires_in_minutes, 54 ) 55 56 dataset_upload_target.additional_properties = d 57 return dataset_upload_target
16@_attrs_define 17class DatasetVersion: 18 """One successfully ingested upload. Cadence and timestamp unit are discovered from the file, 19 not declared by the caller. 20 21 Attributes: 22 dataset_id (str): Example: ds_3f9a1c2e7b0d4a5f. 23 id (str | Unset): The version id. Pass as `datasetVersionId` on `POST .../prepare` to pin it. Example: 24 dsv_8e2b4f19c6a03d7e. 25 bytes_ (int | Unset): Size of the uploaded file. Example: 4831022. 26 rows (int | Unset): Number of data rows. Example: 86400. 27 cadence (str | Unset): The discovered bar cadence (e.g. `1s`, `1m`, `1h`). Example: 1s. 28 timestamp_unit (DatasetVersionTimestampUnit | Unset): The unit the `timestamp` column was uploaded in — 29 ISO-8601, or the epoch band its 30 numeric values fell in (seconds, millis, or micros). 31 Example: iso. 32 gaps (int | Unset): Number of gaps at the discovered cadence. 33 largest_gap_steps (int | Unset): The largest gap, in units of the discovered cadence step. 34 """ 35 36 dataset_id: str 37 id: str | Unset = UNSET 38 bytes_: int | Unset = UNSET 39 rows: int | Unset = UNSET 40 cadence: str | Unset = UNSET 41 timestamp_unit: DatasetVersionTimestampUnit | Unset = UNSET 42 gaps: int | Unset = UNSET 43 largest_gap_steps: int | Unset = UNSET 44 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 45 46 def to_dict(self) -> dict[str, Any]: 47 dataset_id = self.dataset_id 48 49 id = self.id 50 51 bytes_ = self.bytes_ 52 53 rows = self.rows 54 55 cadence = self.cadence 56 57 timestamp_unit: str | Unset = UNSET 58 if not isinstance(self.timestamp_unit, Unset): 59 timestamp_unit = self.timestamp_unit.value 60 61 gaps = self.gaps 62 63 largest_gap_steps = self.largest_gap_steps 64 65 field_dict: dict[str, Any] = {} 66 field_dict.update(self.additional_properties) 67 field_dict.update( 68 { 69 "datasetId": dataset_id, 70 } 71 ) 72 if id is not UNSET: 73 field_dict["id"] = id 74 if bytes_ is not UNSET: 75 field_dict["bytes"] = bytes_ 76 if rows is not UNSET: 77 field_dict["rows"] = rows 78 if cadence is not UNSET: 79 field_dict["cadence"] = cadence 80 if timestamp_unit is not UNSET: 81 field_dict["timestampUnit"] = timestamp_unit 82 if gaps is not UNSET: 83 field_dict["gaps"] = gaps 84 if largest_gap_steps is not UNSET: 85 field_dict["largestGapSteps"] = largest_gap_steps 86 87 return field_dict 88 89 @classmethod 90 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 91 d = dict(src_dict) 92 dataset_id = d.pop("datasetId") 93 94 id = d.pop("id", UNSET) 95 96 bytes_ = d.pop("bytes", UNSET) 97 98 rows = d.pop("rows", UNSET) 99 100 cadence = d.pop("cadence", UNSET) 101 102 _timestamp_unit = d.pop("timestampUnit", UNSET) 103 timestamp_unit: DatasetVersionTimestampUnit | Unset 104 if isinstance(_timestamp_unit, Unset): 105 timestamp_unit = UNSET 106 else: 107 timestamp_unit = DatasetVersionTimestampUnit(_timestamp_unit) 108 109 gaps = d.pop("gaps", UNSET) 110 111 largest_gap_steps = d.pop("largestGapSteps", UNSET) 112 113 dataset_version = cls( 114 dataset_id=dataset_id, 115 id=id, 116 bytes_=bytes_, 117 rows=rows, 118 cadence=cadence, 119 timestamp_unit=timestamp_unit, 120 gaps=gaps, 121 largest_gap_steps=largest_gap_steps, 122 ) 123 124 dataset_version.additional_properties = d 125 return dataset_version 126 127 @property 128 def additional_keys(self) -> list[str]: 129 return list(self.additional_properties.keys()) 130 131 def __getitem__(self, key: str) -> Any: 132 return self.additional_properties[key] 133 134 def __setitem__(self, key: str, value: Any) -> None: 135 self.additional_properties[key] = value 136 137 def __delitem__(self, key: str) -> None: 138 del self.additional_properties[key] 139 140 def __contains__(self, key: str) -> bool: 141 return key in self.additional_properties
One successfully ingested upload. Cadence and timestamp unit are discovered from the file, not declared by the caller.
Attributes:
dataset_id (str): Example: ds_3f9a1c2e7b0d4a5f.
id (str | Unset): The version id. Pass as `datasetVersionId` on `POST .../prepare` to pin it. Example:
dsv_8e2b4f19c6a03d7e.
bytes_ (int | Unset): Size of the uploaded file. Example: 4831022.
rows (int | Unset): Number of data rows. Example: 86400.
cadence (str | Unset): The discovered bar cadence (e.g. `1s`, `1m`, `1h`). Example: 1s.
timestamp_unit (DatasetVersionTimestampUnit | Unset): The unit the `timestamp` column was uploaded in —
ISO-8601, or the epoch band its
numeric values fell in (seconds, millis, or micros).
Example: iso.
gaps (int | Unset): Number of gaps at the discovered cadence.
largest_gap_steps (int | Unset): The largest gap, in units of the discovered cadence step.
31def __init__(self, dataset_id, id=attr_dict['id'].default, bytes_=attr_dict['bytes_'].default, rows=attr_dict['rows'].default, cadence=attr_dict['cadence'].default, timestamp_unit=attr_dict['timestamp_unit'].default, gaps=attr_dict['gaps'].default, largest_gap_steps=attr_dict['largest_gap_steps'].default): 32 self.dataset_id = dataset_id 33 self.id = id 34 self.bytes_ = bytes_ 35 self.rows = rows 36 self.cadence = cadence 37 self.timestamp_unit = timestamp_unit 38 self.gaps = gaps 39 self.largest_gap_steps = largest_gap_steps 40 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetVersion.
46 def to_dict(self) -> dict[str, Any]: 47 dataset_id = self.dataset_id 48 49 id = self.id 50 51 bytes_ = self.bytes_ 52 53 rows = self.rows 54 55 cadence = self.cadence 56 57 timestamp_unit: str | Unset = UNSET 58 if not isinstance(self.timestamp_unit, Unset): 59 timestamp_unit = self.timestamp_unit.value 60 61 gaps = self.gaps 62 63 largest_gap_steps = self.largest_gap_steps 64 65 field_dict: dict[str, Any] = {} 66 field_dict.update(self.additional_properties) 67 field_dict.update( 68 { 69 "datasetId": dataset_id, 70 } 71 ) 72 if id is not UNSET: 73 field_dict["id"] = id 74 if bytes_ is not UNSET: 75 field_dict["bytes"] = bytes_ 76 if rows is not UNSET: 77 field_dict["rows"] = rows 78 if cadence is not UNSET: 79 field_dict["cadence"] = cadence 80 if timestamp_unit is not UNSET: 81 field_dict["timestampUnit"] = timestamp_unit 82 if gaps is not UNSET: 83 field_dict["gaps"] = gaps 84 if largest_gap_steps is not UNSET: 85 field_dict["largestGapSteps"] = largest_gap_steps 86 87 return field_dict
89 @classmethod 90 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 91 d = dict(src_dict) 92 dataset_id = d.pop("datasetId") 93 94 id = d.pop("id", UNSET) 95 96 bytes_ = d.pop("bytes", UNSET) 97 98 rows = d.pop("rows", UNSET) 99 100 cadence = d.pop("cadence", UNSET) 101 102 _timestamp_unit = d.pop("timestampUnit", UNSET) 103 timestamp_unit: DatasetVersionTimestampUnit | Unset 104 if isinstance(_timestamp_unit, Unset): 105 timestamp_unit = UNSET 106 else: 107 timestamp_unit = DatasetVersionTimestampUnit(_timestamp_unit) 108 109 gaps = d.pop("gaps", UNSET) 110 111 largest_gap_steps = d.pop("largestGapSteps", UNSET) 112 113 dataset_version = cls( 114 dataset_id=dataset_id, 115 id=id, 116 bytes_=bytes_, 117 rows=rows, 118 cadence=cadence, 119 timestamp_unit=timestamp_unit, 120 gaps=gaps, 121 largest_gap_steps=largest_gap_steps, 122 ) 123 124 dataset_version.additional_properties = d 125 return dataset_version
5class DatasetVersionTimestampUnit(str, Enum): 6 ISO = "iso" 7 MS = "ms" 8 S = "s" 9 US = "us" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
22@_attrs_define 23class DatasetWithLinks: 24 """A `Dataset` plus a self link. Returned by `GET /datasets/{datasetId}`. 25 26 Attributes: 27 dataset_id (str): Opaque id, returned by `POST /datasets`. Example: ds_3f9a1c2e7b0d4a5f. 28 name (str): Unique among your datasets. Example: My BTC ticks. 29 type_ (DatasetType): Always `ticker` in v1. Example: ticker. 30 instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT. 31 created_at (datetime.datetime): When the dataset was created. Example: 2026-08-20T09:00:00Z. 32 current_version_id (str | Unset): The id of the most recently finalized, successfully ingested version. Absent 33 until at 34 least one upload has finished ingesting. 35 Example: dsv_8e2b4f19c6a03d7e. 36 updated_at (datetime.datetime | Unset): When `currentVersionId` last changed. Absent until it has a value. 37 Example: 2026-08-20T09:04:12Z. 38 from_ (datetime.datetime | Unset): Start of `currentVersionId`'s own data range, as discovered at ingest time. 39 Absent 40 until a version exists. 41 Example: 2026-03-01T00:00:00Z. 42 to (datetime.datetime | Unset): End of `currentVersionId`'s own data range, as discovered at ingest time. Absent 43 until 44 a version exists. 45 Example: 2026-03-08T00:00:00Z. 46 cadence (str | Unset): `currentVersionId`'s own discovered bar cadence (e.g. `1s`, `1m`, `1h`). Absent until a 47 version exists. 48 Example: 1m. 49 field_links (DatasetWithLinksLinks | Unset): 50 """ 51 52 dataset_id: str 53 name: str 54 type_: DatasetType 55 instrument: str 56 created_at: datetime.datetime 57 current_version_id: str | Unset = UNSET 58 updated_at: datetime.datetime | Unset = UNSET 59 from_: datetime.datetime | Unset = UNSET 60 to: datetime.datetime | Unset = UNSET 61 cadence: str | Unset = UNSET 62 field_links: DatasetWithLinksLinks | Unset = UNSET 63 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 64 65 def to_dict(self) -> dict[str, Any]: 66 dataset_id = self.dataset_id 67 68 name = self.name 69 70 type_ = self.type_.value 71 72 instrument = self.instrument 73 74 created_at = self.created_at.isoformat() 75 76 current_version_id = self.current_version_id 77 78 updated_at: str | Unset = UNSET 79 if not isinstance(self.updated_at, Unset): 80 updated_at = self.updated_at.isoformat() 81 82 from_: str | Unset = UNSET 83 if not isinstance(self.from_, Unset): 84 from_ = self.from_.isoformat() 85 86 to: str | Unset = UNSET 87 if not isinstance(self.to, Unset): 88 to = self.to.isoformat() 89 90 cadence = self.cadence 91 92 field_links: dict[str, Any] | Unset = UNSET 93 if not isinstance(self.field_links, Unset): 94 field_links = self.field_links.to_dict() 95 96 field_dict: dict[str, Any] = {} 97 field_dict.update(self.additional_properties) 98 field_dict.update( 99 { 100 "datasetId": dataset_id, 101 "name": name, 102 "type": type_, 103 "instrument": instrument, 104 "createdAt": created_at, 105 } 106 ) 107 if current_version_id is not UNSET: 108 field_dict["currentVersionId"] = current_version_id 109 if updated_at is not UNSET: 110 field_dict["updatedAt"] = updated_at 111 if from_ is not UNSET: 112 field_dict["from"] = from_ 113 if to is not UNSET: 114 field_dict["to"] = to 115 if cadence is not UNSET: 116 field_dict["cadence"] = cadence 117 if field_links is not UNSET: 118 field_dict["_links"] = field_links 119 120 return field_dict 121 122 @classmethod 123 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 124 from ..models.dataset_with_links_links import DatasetWithLinksLinks 125 126 d = dict(src_dict) 127 dataset_id = d.pop("datasetId") 128 129 name = d.pop("name") 130 131 type_ = DatasetType(d.pop("type")) 132 133 instrument = d.pop("instrument") 134 135 created_at = isoparse(d.pop("createdAt")) 136 137 current_version_id = d.pop("currentVersionId", UNSET) 138 139 _updated_at = d.pop("updatedAt", UNSET) 140 updated_at: datetime.datetime | Unset 141 if isinstance(_updated_at, Unset): 142 updated_at = UNSET 143 else: 144 updated_at = isoparse(_updated_at) 145 146 _from_ = d.pop("from", UNSET) 147 from_: datetime.datetime | Unset 148 if isinstance(_from_, Unset): 149 from_ = UNSET 150 else: 151 from_ = isoparse(_from_) 152 153 _to = d.pop("to", UNSET) 154 to: datetime.datetime | Unset 155 if isinstance(_to, Unset): 156 to = UNSET 157 else: 158 to = isoparse(_to) 159 160 cadence = d.pop("cadence", UNSET) 161 162 _field_links = d.pop("_links", UNSET) 163 field_links: DatasetWithLinksLinks | Unset 164 if isinstance(_field_links, Unset): 165 field_links = UNSET 166 else: 167 field_links = DatasetWithLinksLinks.from_dict(_field_links) 168 169 dataset_with_links = cls( 170 dataset_id=dataset_id, 171 name=name, 172 type_=type_, 173 instrument=instrument, 174 created_at=created_at, 175 current_version_id=current_version_id, 176 updated_at=updated_at, 177 from_=from_, 178 to=to, 179 cadence=cadence, 180 field_links=field_links, 181 ) 182 183 dataset_with_links.additional_properties = d 184 return dataset_with_links 185 186 @property 187 def additional_keys(self) -> list[str]: 188 return list(self.additional_properties.keys()) 189 190 def __getitem__(self, key: str) -> Any: 191 return self.additional_properties[key] 192 193 def __setitem__(self, key: str, value: Any) -> None: 194 self.additional_properties[key] = value 195 196 def __delitem__(self, key: str) -> None: 197 del self.additional_properties[key] 198 199 def __contains__(self, key: str) -> bool: 200 return key in self.additional_properties
A Dataset plus a self link. Returned by GET /datasets/{datasetId}.
Attributes:
dataset_id (str): Opaque id, returned by POST /datasets. Example: ds_3f9a1c2e7b0d4a5f.
name (str): Unique among your datasets. Example: My BTC ticks.
type_ (DatasetType): Always ticker in v1. Example: ticker.
instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
created_at (datetime.datetime): When the dataset was created. Example: 2026-08-20T09:00:00Z.
current_version_id (str | Unset): The id of the most recently finalized, successfully ingested version. Absent
until at
least one upload has finished ingesting.
Example: dsv_8e2b4f19c6a03d7e.
updated_at (datetime.datetime | Unset): When currentVersionId last changed. Absent until it has a value.
Example: 2026-08-20T09:04:12Z.
from_ (datetime.datetime | Unset): Start of currentVersionId's own data range, as discovered at ingest time.
Absent
until a version exists.
Example: 2026-03-01T00:00:00Z.
to (datetime.datetime | Unset): End of currentVersionId's own data range, as discovered at ingest time. Absent
until
a version exists.
Example: 2026-03-08T00:00:00Z.
cadence (str | Unset): currentVersionId's own discovered bar cadence (e.g. 1s, 1m, 1h). Absent until a
version exists.
Example: 1m.
field_links (DatasetWithLinksLinks | Unset):
34def __init__(self, dataset_id, name, type_, instrument, created_at, current_version_id=attr_dict['current_version_id'].default, updated_at=attr_dict['updated_at'].default, from_=attr_dict['from_'].default, to=attr_dict['to'].default, cadence=attr_dict['cadence'].default, field_links=attr_dict['field_links'].default): 35 self.dataset_id = dataset_id 36 self.name = name 37 self.type_ = type_ 38 self.instrument = instrument 39 self.created_at = created_at 40 self.current_version_id = current_version_id 41 self.updated_at = updated_at 42 self.from_ = from_ 43 self.to = to 44 self.cadence = cadence 45 self.field_links = field_links 46 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetWithLinks.
65 def to_dict(self) -> dict[str, Any]: 66 dataset_id = self.dataset_id 67 68 name = self.name 69 70 type_ = self.type_.value 71 72 instrument = self.instrument 73 74 created_at = self.created_at.isoformat() 75 76 current_version_id = self.current_version_id 77 78 updated_at: str | Unset = UNSET 79 if not isinstance(self.updated_at, Unset): 80 updated_at = self.updated_at.isoformat() 81 82 from_: str | Unset = UNSET 83 if not isinstance(self.from_, Unset): 84 from_ = self.from_.isoformat() 85 86 to: str | Unset = UNSET 87 if not isinstance(self.to, Unset): 88 to = self.to.isoformat() 89 90 cadence = self.cadence 91 92 field_links: dict[str, Any] | Unset = UNSET 93 if not isinstance(self.field_links, Unset): 94 field_links = self.field_links.to_dict() 95 96 field_dict: dict[str, Any] = {} 97 field_dict.update(self.additional_properties) 98 field_dict.update( 99 { 100 "datasetId": dataset_id, 101 "name": name, 102 "type": type_, 103 "instrument": instrument, 104 "createdAt": created_at, 105 } 106 ) 107 if current_version_id is not UNSET: 108 field_dict["currentVersionId"] = current_version_id 109 if updated_at is not UNSET: 110 field_dict["updatedAt"] = updated_at 111 if from_ is not UNSET: 112 field_dict["from"] = from_ 113 if to is not UNSET: 114 field_dict["to"] = to 115 if cadence is not UNSET: 116 field_dict["cadence"] = cadence 117 if field_links is not UNSET: 118 field_dict["_links"] = field_links 119 120 return field_dict
122 @classmethod 123 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 124 from ..models.dataset_with_links_links import DatasetWithLinksLinks 125 126 d = dict(src_dict) 127 dataset_id = d.pop("datasetId") 128 129 name = d.pop("name") 130 131 type_ = DatasetType(d.pop("type")) 132 133 instrument = d.pop("instrument") 134 135 created_at = isoparse(d.pop("createdAt")) 136 137 current_version_id = d.pop("currentVersionId", UNSET) 138 139 _updated_at = d.pop("updatedAt", UNSET) 140 updated_at: datetime.datetime | Unset 141 if isinstance(_updated_at, Unset): 142 updated_at = UNSET 143 else: 144 updated_at = isoparse(_updated_at) 145 146 _from_ = d.pop("from", UNSET) 147 from_: datetime.datetime | Unset 148 if isinstance(_from_, Unset): 149 from_ = UNSET 150 else: 151 from_ = isoparse(_from_) 152 153 _to = d.pop("to", UNSET) 154 to: datetime.datetime | Unset 155 if isinstance(_to, Unset): 156 to = UNSET 157 else: 158 to = isoparse(_to) 159 160 cadence = d.pop("cadence", UNSET) 161 162 _field_links = d.pop("_links", UNSET) 163 field_links: DatasetWithLinksLinks | Unset 164 if isinstance(_field_links, Unset): 165 field_links = UNSET 166 else: 167 field_links = DatasetWithLinksLinks.from_dict(_field_links) 168 169 dataset_with_links = cls( 170 dataset_id=dataset_id, 171 name=name, 172 type_=type_, 173 instrument=instrument, 174 created_at=created_at, 175 current_version_id=current_version_id, 176 updated_at=updated_at, 177 from_=from_, 178 to=to, 179 cadence=cadence, 180 field_links=field_links, 181 ) 182 183 dataset_with_links.additional_properties = d 184 return dataset_with_links
19@_attrs_define 20class DatasetWithLinksLinks: 21 """ 22 Attributes: 23 self_ (DatasetWithLinksLinksSelf | Unset): 24 """ 25 26 self_: DatasetWithLinksLinksSelf | Unset = UNSET 27 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 28 29 def to_dict(self) -> dict[str, Any]: 30 self_: dict[str, Any] | Unset = UNSET 31 if not isinstance(self.self_, Unset): 32 self_ = self.self_.to_dict() 33 34 field_dict: dict[str, Any] = {} 35 field_dict.update(self.additional_properties) 36 field_dict.update({}) 37 if self_ is not UNSET: 38 field_dict["self"] = self_ 39 40 return field_dict 41 42 @classmethod 43 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 44 from ..models.dataset_with_links_links_self import DatasetWithLinksLinksSelf 45 46 d = dict(src_dict) 47 _self_ = d.pop("self", UNSET) 48 self_: DatasetWithLinksLinksSelf | Unset 49 if isinstance(_self_, Unset): 50 self_ = UNSET 51 else: 52 self_ = DatasetWithLinksLinksSelf.from_dict(_self_) 53 54 dataset_with_links_links = cls( 55 self_=self_, 56 ) 57 58 dataset_with_links_links.additional_properties = d 59 return dataset_with_links_links 60 61 @property 62 def additional_keys(self) -> list[str]: 63 return list(self.additional_properties.keys()) 64 65 def __getitem__(self, key: str) -> Any: 66 return self.additional_properties[key] 67 68 def __setitem__(self, key: str, value: Any) -> None: 69 self.additional_properties[key] = value 70 71 def __delitem__(self, key: str) -> None: 72 del self.additional_properties[key] 73 74 def __contains__(self, key: str) -> bool: 75 return key in self.additional_properties
Attributes: self_ (DatasetWithLinksLinksSelf | Unset):
24def __init__(self, self_=attr_dict['self_'].default): 25 self.self_ = self_ 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetWithLinksLinks.
29 def to_dict(self) -> dict[str, Any]: 30 self_: dict[str, Any] | Unset = UNSET 31 if not isinstance(self.self_, Unset): 32 self_ = self.self_.to_dict() 33 34 field_dict: dict[str, Any] = {} 35 field_dict.update(self.additional_properties) 36 field_dict.update({}) 37 if self_ is not UNSET: 38 field_dict["self"] = self_ 39 40 return field_dict
42 @classmethod 43 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 44 from ..models.dataset_with_links_links_self import DatasetWithLinksLinksSelf 45 46 d = dict(src_dict) 47 _self_ = d.pop("self", UNSET) 48 self_: DatasetWithLinksLinksSelf | Unset 49 if isinstance(_self_, Unset): 50 self_ = UNSET 51 else: 52 self_ = DatasetWithLinksLinksSelf.from_dict(_self_) 53 54 dataset_with_links_links = cls( 55 self_=self_, 56 ) 57 58 dataset_with_links_links.additional_properties = d 59 return dataset_with_links_links
15@_attrs_define 16class DatasetWithLinksLinksSelf: 17 """ 18 Attributes: 19 href (str | Unset): Example: /v1/datasets/ds_3f9a1c2e7b0d4a5f. 20 """ 21 22 href: str | Unset = UNSET 23 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 24 25 def to_dict(self) -> dict[str, Any]: 26 href = self.href 27 28 field_dict: dict[str, Any] = {} 29 field_dict.update(self.additional_properties) 30 field_dict.update({}) 31 if href is not UNSET: 32 field_dict["href"] = href 33 34 return field_dict 35 36 @classmethod 37 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 38 d = dict(src_dict) 39 href = d.pop("href", UNSET) 40 41 dataset_with_links_links_self = cls( 42 href=href, 43 ) 44 45 dataset_with_links_links_self.additional_properties = d 46 return dataset_with_links_links_self 47 48 @property 49 def additional_keys(self) -> list[str]: 50 return list(self.additional_properties.keys()) 51 52 def __getitem__(self, key: str) -> Any: 53 return self.additional_properties[key] 54 55 def __setitem__(self, key: str, value: Any) -> None: 56 self.additional_properties[key] = value 57 58 def __delitem__(self, key: str) -> None: 59 del self.additional_properties[key] 60 61 def __contains__(self, key: str) -> bool: 62 return key in self.additional_properties
Attributes: href (str | Unset): Example: /v1/datasets/ds_3f9a1c2e7b0d4a5f.
24def __init__(self, href=attr_dict['href'].default): 25 self.href = href 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DatasetWithLinksLinksSelf.
5class DataSourceType(str, Enum): 6 TICKER = "ticker" 7 8 def __str__(self) -> str: 9 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
15@_attrs_define 16class DeclaredProperty: 17 """One property name `POST /strategy` could establish without constructing the strategy — 18 either declared with `@StrategyProperty` on the compiled source, or one of the small set of 19 base properties every strategy carries (`amnt`, `enabled`, `multiEntry`, ...). 20 21 **Best-effort, not exhaustive.** A property registered through an attached risk/backtest 22 config needs a live instance to discover and is not listed here. Use this to catch a typo'd 23 sweep key before submitting, not as the definitive list of what a sweep will accept — a 24 name absent from this list may still be valid. 25 26 Attributes: 27 name (str): The key a sweep or execute param map uses for this property. Example: rsi.period. 28 description (str | Unset): Human-readable label, as declared. Example: RSI period. 29 default_value (str | Unset): The declared default, as a string, if one was given. Absent, not null, when none 30 was 31 declared. 32 Example: 14. 33 reflected (bool | Unset): Whether a value for this key is injected into the strategy's field (`true`) or only 34 available through the property map (`false`). 35 Example: True. 36 min_ (float | Unset): Suggested sweep/range minimum, if declared. Advisory only, never validated. Example: 2. 37 max_ (float | Unset): Suggested sweep/range maximum, if declared. Advisory only, never validated. Example: 50. 38 step (float | Unset): Suggested sweep/range step, if declared. Advisory only, never validated. Example: 1. 39 """ 40 41 name: str 42 description: str | Unset = UNSET 43 default_value: str | Unset = UNSET 44 reflected: bool | Unset = UNSET 45 min_: float | Unset = UNSET 46 max_: float | Unset = UNSET 47 step: float | Unset = UNSET 48 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 49 50 def to_dict(self) -> dict[str, Any]: 51 name = self.name 52 53 description = self.description 54 55 default_value = self.default_value 56 57 reflected = self.reflected 58 59 min_ = self.min_ 60 61 max_ = self.max_ 62 63 step = self.step 64 65 field_dict: dict[str, Any] = {} 66 field_dict.update(self.additional_properties) 67 field_dict.update( 68 { 69 "name": name, 70 } 71 ) 72 if description is not UNSET: 73 field_dict["description"] = description 74 if default_value is not UNSET: 75 field_dict["defaultValue"] = default_value 76 if reflected is not UNSET: 77 field_dict["reflected"] = reflected 78 if min_ is not UNSET: 79 field_dict["min"] = min_ 80 if max_ is not UNSET: 81 field_dict["max"] = max_ 82 if step is not UNSET: 83 field_dict["step"] = step 84 85 return field_dict 86 87 @classmethod 88 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 89 d = dict(src_dict) 90 name = d.pop("name") 91 92 description = d.pop("description", UNSET) 93 94 default_value = d.pop("defaultValue", UNSET) 95 96 reflected = d.pop("reflected", UNSET) 97 98 min_ = d.pop("min", UNSET) 99 100 max_ = d.pop("max", UNSET) 101 102 step = d.pop("step", UNSET) 103 104 declared_property = cls( 105 name=name, 106 description=description, 107 default_value=default_value, 108 reflected=reflected, 109 min_=min_, 110 max_=max_, 111 step=step, 112 ) 113 114 declared_property.additional_properties = d 115 return declared_property 116 117 @property 118 def additional_keys(self) -> list[str]: 119 return list(self.additional_properties.keys()) 120 121 def __getitem__(self, key: str) -> Any: 122 return self.additional_properties[key] 123 124 def __setitem__(self, key: str, value: Any) -> None: 125 self.additional_properties[key] = value 126 127 def __delitem__(self, key: str) -> None: 128 del self.additional_properties[key] 129 130 def __contains__(self, key: str) -> bool: 131 return key in self.additional_properties
One property name POST /strategy could establish without constructing the strategy —
either declared with @StrategyProperty on the compiled source, or one of the small set of
base properties every strategy carries (amnt, enabled, multiEntry, ...).
Best-effort, not exhaustive. A property registered through an attached risk/backtest config needs a live instance to discover and is not listed here. Use this to catch a typo'd sweep key before submitting, not as the definitive list of what a sweep will accept — a name absent from this list may still be valid.
Attributes:
name (str): The key a sweep or execute param map uses for this property. Example: rsi.period.
description (str | Unset): Human-readable label, as declared. Example: RSI period.
default_value (str | Unset): The declared default, as a string, if one was given. Absent, not null, when none
was
declared.
Example: 14.
reflected (bool | Unset): Whether a value for this key is injected into the strategy's field (`true`) or only
available through the property map (`false`).
Example: True.
min_ (float | Unset): Suggested sweep/range minimum, if declared. Advisory only, never validated. Example: 2.
max_ (float | Unset): Suggested sweep/range maximum, if declared. Advisory only, never validated. Example: 50.
step (float | Unset): Suggested sweep/range step, if declared. Advisory only, never validated. Example: 1.
30def __init__(self, name, description=attr_dict['description'].default, default_value=attr_dict['default_value'].default, reflected=attr_dict['reflected'].default, min_=attr_dict['min_'].default, max_=attr_dict['max_'].default, step=attr_dict['step'].default): 31 self.name = name 32 self.description = description 33 self.default_value = default_value 34 self.reflected = reflected 35 self.min_ = min_ 36 self.max_ = max_ 37 self.step = step 38 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DeclaredProperty.
50 def to_dict(self) -> dict[str, Any]: 51 name = self.name 52 53 description = self.description 54 55 default_value = self.default_value 56 57 reflected = self.reflected 58 59 min_ = self.min_ 60 61 max_ = self.max_ 62 63 step = self.step 64 65 field_dict: dict[str, Any] = {} 66 field_dict.update(self.additional_properties) 67 field_dict.update( 68 { 69 "name": name, 70 } 71 ) 72 if description is not UNSET: 73 field_dict["description"] = description 74 if default_value is not UNSET: 75 field_dict["defaultValue"] = default_value 76 if reflected is not UNSET: 77 field_dict["reflected"] = reflected 78 if min_ is not UNSET: 79 field_dict["min"] = min_ 80 if max_ is not UNSET: 81 field_dict["max"] = max_ 82 if step is not UNSET: 83 field_dict["step"] = step 84 85 return field_dict
87 @classmethod 88 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 89 d = dict(src_dict) 90 name = d.pop("name") 91 92 description = d.pop("description", UNSET) 93 94 default_value = d.pop("defaultValue", UNSET) 95 96 reflected = d.pop("reflected", UNSET) 97 98 min_ = d.pop("min", UNSET) 99 100 max_ = d.pop("max", UNSET) 101 102 step = d.pop("step", UNSET) 103 104 declared_property = cls( 105 name=name, 106 description=description, 107 default_value=default_value, 108 reflected=reflected, 109 min_=min_, 110 max_=max_, 111 step=step, 112 ) 113 114 declared_property.additional_properties = d 115 return declared_property
13@_attrs_define 14class DeleteDatasetResponse200: 15 """ 16 Attributes: 17 dataset_id (str): 18 deleted (bool): 19 """ 20 21 dataset_id: str 22 deleted: bool 23 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 24 25 def to_dict(self) -> dict[str, Any]: 26 dataset_id = self.dataset_id 27 28 deleted = self.deleted 29 30 field_dict: dict[str, Any] = {} 31 field_dict.update(self.additional_properties) 32 field_dict.update( 33 { 34 "datasetId": dataset_id, 35 "deleted": deleted, 36 } 37 ) 38 39 return field_dict 40 41 @classmethod 42 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 43 d = dict(src_dict) 44 dataset_id = d.pop("datasetId") 45 46 deleted = d.pop("deleted") 47 48 delete_dataset_response_200 = cls( 49 dataset_id=dataset_id, 50 deleted=deleted, 51 ) 52 53 delete_dataset_response_200.additional_properties = d 54 return delete_dataset_response_200 55 56 @property 57 def additional_keys(self) -> list[str]: 58 return list(self.additional_properties.keys()) 59 60 def __getitem__(self, key: str) -> Any: 61 return self.additional_properties[key] 62 63 def __setitem__(self, key: str, value: Any) -> None: 64 self.additional_properties[key] = value 65 66 def __delitem__(self, key: str) -> None: 67 del self.additional_properties[key] 68 69 def __contains__(self, key: str) -> bool: 70 return key in self.additional_properties
Attributes: dataset_id (str): deleted (bool):
25def __init__(self, dataset_id, deleted): 26 self.dataset_id = dataset_id 27 self.deleted = deleted 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DeleteDatasetResponse200.
41 @classmethod 42 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 43 d = dict(src_dict) 44 dataset_id = d.pop("datasetId") 45 46 deleted = d.pop("deleted") 47 48 delete_dataset_response_200 = cls( 49 dataset_id=dataset_id, 50 deleted=deleted, 51 ) 52 53 delete_dataset_response_200.additional_properties = d 54 return delete_dataset_response_200
13@_attrs_define 14class DeleteStrategyResponse200: 15 """ 16 Attributes: 17 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 18 always yields the same id, for every caller, whatever its formatting. See 19 `POST /strategy` for exactly which rewrites preserve it and which do not. 20 Example: 6bsh31ikwkuivhtgcoa6s4. 21 deleted (bool): 22 """ 23 24 strategy_id: str 25 deleted: bool 26 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 27 28 def to_dict(self) -> dict[str, Any]: 29 strategy_id = self.strategy_id 30 31 deleted = self.deleted 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "strategyId": strategy_id, 38 "deleted": deleted, 39 } 40 ) 41 42 return field_dict 43 44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 strategy_id = d.pop("strategyId") 48 49 deleted = d.pop("deleted") 50 51 delete_strategy_response_200 = cls( 52 strategy_id=strategy_id, 53 deleted=deleted, 54 ) 55 56 delete_strategy_response_200.additional_properties = d 57 return delete_strategy_response_200 58 59 @property 60 def additional_keys(self) -> list[str]: 61 return list(self.additional_properties.keys()) 62 63 def __getitem__(self, key: str) -> Any: 64 return self.additional_properties[key] 65 66 def __setitem__(self, key: str, value: Any) -> None: 67 self.additional_properties[key] = value 68 69 def __delitem__(self, key: str) -> None: 70 del self.additional_properties[key] 71 72 def __contains__(self, key: str) -> bool: 73 return key in self.additional_properties
Attributes:
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
POST /strategy for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
deleted (bool):
25def __init__(self, strategy_id, deleted): 26 self.strategy_id = strategy_id 27 self.deleted = deleted 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class DeleteStrategyResponse200.
28 def to_dict(self) -> dict[str, Any]: 29 strategy_id = self.strategy_id 30 31 deleted = self.deleted 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "strategyId": strategy_id, 38 "deleted": deleted, 39 } 40 ) 41 42 return field_dict
44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 strategy_id = d.pop("strategyId") 48 49 deleted = d.pop("deleted") 50 51 delete_strategy_response_200 = cls( 52 strategy_id=strategy_id, 53 deleted=deleted, 54 ) 55 56 delete_strategy_response_200.additional_properties = d 57 return delete_strategy_response_200
5class DownloadKlinesFormat(str, Enum): 6 LASTRA = "lastra" 7 PARQUET = "parquet" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class DownloadTickersFormat(str, Enum): 6 LASTRA = "lastra" 7 PARQUET = "parquet" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
15@_attrs_define 16class EquityCurveMeta: 17 """What the transform pipeline actually did, computed from the observed outcome — never a copy of what was requested. 18 Lets a caller detect a forced or no-op transform (e.g. a `resample` ceiling already above the curve's size is a 19 legal no-op, reported honestly as `resampled: false`). 20 21 Attributes: 22 input_point_count (int): Size of the curve the transform pipeline received. Example: 100000. 23 output_point_count (int): Size after the full pipeline (resample, then differential, then outMode). Example: 24 100. 25 resampled (bool): True only if the resample stage actually changed the point count. 26 differential (bool): True only if delta-encoding actually ran. Requesting it on a curve of 0 or 1 points has 27 nothing to encode, so it does not run even if asked. 28 out_mode (EquityCurveOutMode): JSON shape for an equity curve's points. `ARRAY` is `[{timestamp, equity}, ...]`; 29 `SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The one schema shared 30 by every place `outMode` appears, request or response, so the two cannot drift to different value sets. 31 """ 32 33 input_point_count: int 34 output_point_count: int 35 resampled: bool 36 differential: bool 37 out_mode: EquityCurveOutMode 38 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 39 40 def to_dict(self) -> dict[str, Any]: 41 input_point_count = self.input_point_count 42 43 output_point_count = self.output_point_count 44 45 resampled = self.resampled 46 47 differential = self.differential 48 49 out_mode = self.out_mode.value 50 51 field_dict: dict[str, Any] = {} 52 field_dict.update(self.additional_properties) 53 field_dict.update( 54 { 55 "inputPointCount": input_point_count, 56 "outputPointCount": output_point_count, 57 "resampled": resampled, 58 "differential": differential, 59 "outMode": out_mode, 60 } 61 ) 62 63 return field_dict 64 65 @classmethod 66 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 67 d = dict(src_dict) 68 input_point_count = d.pop("inputPointCount") 69 70 output_point_count = d.pop("outputPointCount") 71 72 resampled = d.pop("resampled") 73 74 differential = d.pop("differential") 75 76 out_mode = EquityCurveOutMode(d.pop("outMode")) 77 78 equity_curve_meta = cls( 79 input_point_count=input_point_count, 80 output_point_count=output_point_count, 81 resampled=resampled, 82 differential=differential, 83 out_mode=out_mode, 84 ) 85 86 equity_curve_meta.additional_properties = d 87 return equity_curve_meta 88 89 @property 90 def additional_keys(self) -> list[str]: 91 return list(self.additional_properties.keys()) 92 93 def __getitem__(self, key: str) -> Any: 94 return self.additional_properties[key] 95 96 def __setitem__(self, key: str, value: Any) -> None: 97 self.additional_properties[key] = value 98 99 def __delitem__(self, key: str) -> None: 100 del self.additional_properties[key] 101 102 def __contains__(self, key: str) -> bool: 103 return key in self.additional_properties
What the transform pipeline actually did, computed from the observed outcome — never a copy of what was requested.
Lets a caller detect a forced or no-op transform (e.g. a resample ceiling already above the curve's size is a
legal no-op, reported honestly as resampled: false).
Attributes:
input_point_count (int): Size of the curve the transform pipeline received. Example: 100000.
output_point_count (int): Size after the full pipeline (resample, then differential, then outMode). Example:
100.
resampled (bool): True only if the resample stage actually changed the point count.
differential (bool): True only if delta-encoding actually ran. Requesting it on a curve of 0 or 1 points has
nothing to encode, so it does not run even if asked.
out_mode (EquityCurveOutMode): JSON shape for an equity curve's points. `ARRAY` is `[{timestamp, equity}, ...]`;
`SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The one schema shared
by every place `outMode` appears, request or response, so the two cannot drift to different value sets.
28def __init__(self, input_point_count, output_point_count, resampled, differential, out_mode): 29 self.input_point_count = input_point_count 30 self.output_point_count = output_point_count 31 self.resampled = resampled 32 self.differential = differential 33 self.out_mode = out_mode 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class EquityCurveMeta.
40 def to_dict(self) -> dict[str, Any]: 41 input_point_count = self.input_point_count 42 43 output_point_count = self.output_point_count 44 45 resampled = self.resampled 46 47 differential = self.differential 48 49 out_mode = self.out_mode.value 50 51 field_dict: dict[str, Any] = {} 52 field_dict.update(self.additional_properties) 53 field_dict.update( 54 { 55 "inputPointCount": input_point_count, 56 "outputPointCount": output_point_count, 57 "resampled": resampled, 58 "differential": differential, 59 "outMode": out_mode, 60 } 61 ) 62 63 return field_dict
65 @classmethod 66 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 67 d = dict(src_dict) 68 input_point_count = d.pop("inputPointCount") 69 70 output_point_count = d.pop("outputPointCount") 71 72 resampled = d.pop("resampled") 73 74 differential = d.pop("differential") 75 76 out_mode = EquityCurveOutMode(d.pop("outMode")) 77 78 equity_curve_meta = cls( 79 input_point_count=input_point_count, 80 output_point_count=output_point_count, 81 resampled=resampled, 82 differential=differential, 83 out_mode=out_mode, 84 ) 85 86 equity_curve_meta.additional_properties = d 87 return equity_curve_meta
16@_attrs_define 17class EquityCurveOptions: 18 """Requested equity-curve transform, applied server-side in a fixed pipeline order: `resample` (point count) then 19 `differential` (encoding) then `outMode` (JSON shape) — each stage assumes the previous one already ran. A server- 20 side size guard can still force a smaller/deflated shape above its thresholds regardless of what is requested here — 21 see `EquityCurveMeta` for what actually happened. 22 23 Attributes: 24 resample (int | Unset): Downsample to at most this many points (extrema-preserving — the global max/min and the 25 exact first/last point are always kept). Omit for no downsampling. 26 differential (bool | Unset): Delta-encode both fields from the second (post-resample) point onward. Default: 27 False. 28 out_mode (EquityCurveOutMode | Unset): JSON shape for an equity curve's points. `ARRAY` is `[{timestamp, 29 equity}, ...]`; `SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The 30 one schema shared by every place `outMode` appears, request or response, so the two cannot drift to different 31 value sets. Default: EquityCurveOutMode.ARRAY. 32 """ 33 34 resample: int | Unset = UNSET 35 differential: bool | Unset = False 36 out_mode: EquityCurveOutMode | Unset = EquityCurveOutMode.ARRAY 37 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 38 39 def to_dict(self) -> dict[str, Any]: 40 resample = self.resample 41 42 differential = self.differential 43 44 out_mode: str | Unset = UNSET 45 if not isinstance(self.out_mode, Unset): 46 out_mode = self.out_mode.value 47 48 field_dict: dict[str, Any] = {} 49 field_dict.update(self.additional_properties) 50 field_dict.update({}) 51 if resample is not UNSET: 52 field_dict["resample"] = resample 53 if differential is not UNSET: 54 field_dict["differential"] = differential 55 if out_mode is not UNSET: 56 field_dict["outMode"] = out_mode 57 58 return field_dict 59 60 @classmethod 61 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 62 d = dict(src_dict) 63 resample = d.pop("resample", UNSET) 64 65 differential = d.pop("differential", UNSET) 66 67 _out_mode = d.pop("outMode", UNSET) 68 out_mode: EquityCurveOutMode | Unset 69 if isinstance(_out_mode, Unset): 70 out_mode = UNSET 71 else: 72 out_mode = EquityCurveOutMode(_out_mode) 73 74 equity_curve_options = cls( 75 resample=resample, 76 differential=differential, 77 out_mode=out_mode, 78 ) 79 80 equity_curve_options.additional_properties = d 81 return equity_curve_options 82 83 @property 84 def additional_keys(self) -> list[str]: 85 return list(self.additional_properties.keys()) 86 87 def __getitem__(self, key: str) -> Any: 88 return self.additional_properties[key] 89 90 def __setitem__(self, key: str, value: Any) -> None: 91 self.additional_properties[key] = value 92 93 def __delitem__(self, key: str) -> None: 94 del self.additional_properties[key] 95 96 def __contains__(self, key: str) -> bool: 97 return key in self.additional_properties
Requested equity-curve transform, applied server-side in a fixed pipeline order: resample (point count) then
differential (encoding) then outMode (JSON shape) — each stage assumes the previous one already ran. A server-
side size guard can still force a smaller/deflated shape above its thresholds regardless of what is requested here —
see EquityCurveMeta for what actually happened.
Attributes:
resample (int | Unset): Downsample to at most this many points (extrema-preserving — the global max/min and the
exact first/last point are always kept). Omit for no downsampling.
differential (bool | Unset): Delta-encode both fields from the second (post-resample) point onward. Default:
False.
out_mode (EquityCurveOutMode | Unset): JSON shape for an equity curve's points. `ARRAY` is `[{timestamp,
equity}, ...]`; `SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The
one schema shared by every place `outMode` appears, request or response, so the two cannot drift to different
value sets. Default: EquityCurveOutMode.ARRAY.
26def __init__(self, resample=attr_dict['resample'].default, differential=attr_dict['differential'].default, out_mode=attr_dict['out_mode'].default): 27 self.resample = resample 28 self.differential = differential 29 self.out_mode = out_mode 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class EquityCurveOptions.
39 def to_dict(self) -> dict[str, Any]: 40 resample = self.resample 41 42 differential = self.differential 43 44 out_mode: str | Unset = UNSET 45 if not isinstance(self.out_mode, Unset): 46 out_mode = self.out_mode.value 47 48 field_dict: dict[str, Any] = {} 49 field_dict.update(self.additional_properties) 50 field_dict.update({}) 51 if resample is not UNSET: 52 field_dict["resample"] = resample 53 if differential is not UNSET: 54 field_dict["differential"] = differential 55 if out_mode is not UNSET: 56 field_dict["outMode"] = out_mode 57 58 return field_dict
60 @classmethod 61 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 62 d = dict(src_dict) 63 resample = d.pop("resample", UNSET) 64 65 differential = d.pop("differential", UNSET) 66 67 _out_mode = d.pop("outMode", UNSET) 68 out_mode: EquityCurveOutMode | Unset 69 if isinstance(_out_mode, Unset): 70 out_mode = UNSET 71 else: 72 out_mode = EquityCurveOutMode(_out_mode) 73 74 equity_curve_options = cls( 75 resample=resample, 76 differential=differential, 77 out_mode=out_mode, 78 ) 79 80 equity_curve_options.additional_properties = d 81 return equity_curve_options
5class EquityCurveOutMode(str, Enum): 6 ARRAY = "ARRAY" 7 SHORT = "SHORT" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class EquityCurveRequest: 19 """Selection (`mode`/`n`/`maxPct`) plus the transform preference (`resample`/`differential`/`outMode`) applied by `GET 20 .../equityCurve` whenever ITS OWN query params are absent, for a curve this sweep retained. The transform half never 21 affects retention or `sweepId` — a caller can always override it per-request at read time regardless of what was 22 submitted here. 23 24 Attributes: 25 resample (int | Unset): Downsample to at most this many points (extrema-preserving — the global max/min and the 26 exact first/last point are always kept). Omit for no downsampling. 27 differential (bool | Unset): Delta-encode both fields from the second (post-resample) point onward. Default: 28 False. 29 out_mode (EquityCurveOutMode | Unset): JSON shape for an equity curve's points. `ARRAY` is `[{timestamp, 30 equity}, ...]`; `SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The 31 one schema shared by every place `outMode` appears, request or response, so the two cannot drift to different 32 value sets. Default: EquityCurveOutMode.ARRAY. 33 mode (EquityCurveRequestMode | Unset): Which trials keep their per-point equity curve. `auto` retains curves 34 only while the accumulated size stays within server limits; `topN`/`topPct` retain curves for the best-ranked 35 trials explicitly; `none` retains no curves. Default: EquityCurveRequestMode.AUTO. 36 n (int | Unset): Trial count to retain when mode is topN. 37 max_pct (float | Unset): Top percentage of trials to retain when mode is topPct. 38 """ 39 40 resample: int | Unset = UNSET 41 differential: bool | Unset = False 42 out_mode: EquityCurveOutMode | Unset = EquityCurveOutMode.ARRAY 43 mode: EquityCurveRequestMode | Unset = EquityCurveRequestMode.AUTO 44 n: int | Unset = UNSET 45 max_pct: float | Unset = UNSET 46 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 47 48 def to_dict(self) -> dict[str, Any]: 49 resample = self.resample 50 51 differential = self.differential 52 53 out_mode: str | Unset = UNSET 54 if not isinstance(self.out_mode, Unset): 55 out_mode = self.out_mode.value 56 57 mode: str | Unset = UNSET 58 if not isinstance(self.mode, Unset): 59 mode = self.mode.value 60 61 n = self.n 62 63 max_pct = self.max_pct 64 65 field_dict: dict[str, Any] = {} 66 field_dict.update(self.additional_properties) 67 field_dict.update({}) 68 if resample is not UNSET: 69 field_dict["resample"] = resample 70 if differential is not UNSET: 71 field_dict["differential"] = differential 72 if out_mode is not UNSET: 73 field_dict["outMode"] = out_mode 74 if mode is not UNSET: 75 field_dict["mode"] = mode 76 if n is not UNSET: 77 field_dict["n"] = n 78 if max_pct is not UNSET: 79 field_dict["maxPct"] = max_pct 80 81 return field_dict 82 83 @classmethod 84 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 85 d = dict(src_dict) 86 resample = d.pop("resample", UNSET) 87 88 differential = d.pop("differential", UNSET) 89 90 _out_mode = d.pop("outMode", UNSET) 91 out_mode: EquityCurveOutMode | Unset 92 if isinstance(_out_mode, Unset): 93 out_mode = UNSET 94 else: 95 out_mode = EquityCurveOutMode(_out_mode) 96 97 _mode = d.pop("mode", UNSET) 98 mode: EquityCurveRequestMode | Unset 99 if isinstance(_mode, Unset): 100 mode = UNSET 101 else: 102 mode = EquityCurveRequestMode(_mode) 103 104 n = d.pop("n", UNSET) 105 106 max_pct = d.pop("maxPct", UNSET) 107 108 equity_curve_request = cls( 109 resample=resample, 110 differential=differential, 111 out_mode=out_mode, 112 mode=mode, 113 n=n, 114 max_pct=max_pct, 115 ) 116 117 equity_curve_request.additional_properties = d 118 return equity_curve_request 119 120 @property 121 def additional_keys(self) -> list[str]: 122 return list(self.additional_properties.keys()) 123 124 def __getitem__(self, key: str) -> Any: 125 return self.additional_properties[key] 126 127 def __setitem__(self, key: str, value: Any) -> None: 128 self.additional_properties[key] = value 129 130 def __delitem__(self, key: str) -> None: 131 del self.additional_properties[key] 132 133 def __contains__(self, key: str) -> bool: 134 return key in self.additional_properties
Selection (mode/n/maxPct) plus the transform preference (resample/differential/outMode) applied by GET
.../equityCurve whenever ITS OWN query params are absent, for a curve this sweep retained. The transform half never
affects retention or sweepId — a caller can always override it per-request at read time regardless of what was
submitted here.
Attributes:
resample (int | Unset): Downsample to at most this many points (extrema-preserving — the global max/min and the
exact first/last point are always kept). Omit for no downsampling.
differential (bool | Unset): Delta-encode both fields from the second (post-resample) point onward. Default:
False.
out_mode (EquityCurveOutMode | Unset): JSON shape for an equity curve's points. `ARRAY` is `[{timestamp,
equity}, ...]`; `SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The
one schema shared by every place `outMode` appears, request or response, so the two cannot drift to different
value sets. Default: EquityCurveOutMode.ARRAY.
mode (EquityCurveRequestMode | Unset): Which trials keep their per-point equity curve. `auto` retains curves
only while the accumulated size stays within server limits; `topN`/`topPct` retain curves for the best-ranked
trials explicitly; `none` retains no curves. Default: EquityCurveRequestMode.AUTO.
n (int | Unset): Trial count to retain when mode is topN.
max_pct (float | Unset): Top percentage of trials to retain when mode is topPct.
29def __init__(self, resample=attr_dict['resample'].default, differential=attr_dict['differential'].default, out_mode=attr_dict['out_mode'].default, mode=attr_dict['mode'].default, n=attr_dict['n'].default, max_pct=attr_dict['max_pct'].default): 30 self.resample = resample 31 self.differential = differential 32 self.out_mode = out_mode 33 self.mode = mode 34 self.n = n 35 self.max_pct = max_pct 36 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class EquityCurveRequest.
48 def to_dict(self) -> dict[str, Any]: 49 resample = self.resample 50 51 differential = self.differential 52 53 out_mode: str | Unset = UNSET 54 if not isinstance(self.out_mode, Unset): 55 out_mode = self.out_mode.value 56 57 mode: str | Unset = UNSET 58 if not isinstance(self.mode, Unset): 59 mode = self.mode.value 60 61 n = self.n 62 63 max_pct = self.max_pct 64 65 field_dict: dict[str, Any] = {} 66 field_dict.update(self.additional_properties) 67 field_dict.update({}) 68 if resample is not UNSET: 69 field_dict["resample"] = resample 70 if differential is not UNSET: 71 field_dict["differential"] = differential 72 if out_mode is not UNSET: 73 field_dict["outMode"] = out_mode 74 if mode is not UNSET: 75 field_dict["mode"] = mode 76 if n is not UNSET: 77 field_dict["n"] = n 78 if max_pct is not UNSET: 79 field_dict["maxPct"] = max_pct 80 81 return field_dict
83 @classmethod 84 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 85 d = dict(src_dict) 86 resample = d.pop("resample", UNSET) 87 88 differential = d.pop("differential", UNSET) 89 90 _out_mode = d.pop("outMode", UNSET) 91 out_mode: EquityCurveOutMode | Unset 92 if isinstance(_out_mode, Unset): 93 out_mode = UNSET 94 else: 95 out_mode = EquityCurveOutMode(_out_mode) 96 97 _mode = d.pop("mode", UNSET) 98 mode: EquityCurveRequestMode | Unset 99 if isinstance(_mode, Unset): 100 mode = UNSET 101 else: 102 mode = EquityCurveRequestMode(_mode) 103 104 n = d.pop("n", UNSET) 105 106 max_pct = d.pop("maxPct", UNSET) 107 108 equity_curve_request = cls( 109 resample=resample, 110 differential=differential, 111 out_mode=out_mode, 112 mode=mode, 113 n=n, 114 max_pct=max_pct, 115 ) 116 117 equity_curve_request.additional_properties = d 118 return equity_curve_request
5class EquityCurveRequestMode(str, Enum): 6 AUTO = "auto" 7 NONE = "none" 8 TOPN = "topN" 9 TOPPCT = "topPct" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
20@_attrs_define 21class EquityCurveResult: 22 """An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`, `timestamps` + `equities` (parallel arrays) when 23 `SHORT`. Used identically wherever a curve is returned — a plain backtest's inline `equityCurve` and a sweep row's 24 `equityCurve` are the same type. `url` is present *instead of* any points when the curve is served by pointer rather 25 than inline (a sweep row's top-N winners only): `GET` it separately to fetch this exact same shape with the points 26 populated. 27 28 Attributes: 29 meta (EquityCurveMeta): What the transform pipeline actually did, computed from the observed outcome — never a 30 copy of what was requested. Lets a caller detect a forced or no-op transform (e.g. a `resample` ceiling already 31 above the curve's size is a legal no-op, reported honestly as `resampled: false`). 32 points (list[EquityPoint] | Unset): Present when `meta.outMode` is `ARRAY` and the curve is inline (not a 33 pointer). 34 timestamps (list[int] | Unset): Present when `meta.outMode` is `SHORT` and the curve is inline (not a pointer). 35 equities (list[float] | Unset): Present when `meta.outMode` is `SHORT` and the curve is inline (not a pointer), 36 parallel to `timestamps` (same index, same point). 37 url (str | Unset): Present only for a sweep row's pointer curve. `GET` this to fetch the curve itself, in this 38 exact `{points|timestamps+equities, meta}` shape — `meta` there is the real, possibly size-guarded outcome; this 39 outer `meta` is a raw, untransformed preview from the moment the sweep selected this trial's curve, and the two 40 can legitimately differ. Example: /v1/backtest/binance/ticker/executeSweep/req-1/swp_test/runs/3/equityCurve. 41 """ 42 43 meta: EquityCurveMeta 44 points: list[EquityPoint] | Unset = UNSET 45 timestamps: list[int] | Unset = UNSET 46 equities: list[float] | Unset = UNSET 47 url: str | Unset = UNSET 48 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 49 50 def to_dict(self) -> dict[str, Any]: 51 meta = self.meta.to_dict() 52 53 points: list[dict[str, Any]] | Unset = UNSET 54 if not isinstance(self.points, Unset): 55 points = [] 56 for points_item_data in self.points: 57 points_item = points_item_data.to_dict() 58 points.append(points_item) 59 60 timestamps: list[int] | Unset = UNSET 61 if not isinstance(self.timestamps, Unset): 62 timestamps = self.timestamps 63 64 equities: list[float] | Unset = UNSET 65 if not isinstance(self.equities, Unset): 66 equities = self.equities 67 68 url = self.url 69 70 field_dict: dict[str, Any] = {} 71 field_dict.update(self.additional_properties) 72 field_dict.update( 73 { 74 "meta": meta, 75 } 76 ) 77 if points is not UNSET: 78 field_dict["points"] = points 79 if timestamps is not UNSET: 80 field_dict["timestamps"] = timestamps 81 if equities is not UNSET: 82 field_dict["equities"] = equities 83 if url is not UNSET: 84 field_dict["url"] = url 85 86 return field_dict 87 88 @classmethod 89 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 90 from ..models.equity_curve_meta import EquityCurveMeta 91 from ..models.equity_point import EquityPoint 92 93 d = dict(src_dict) 94 meta = EquityCurveMeta.from_dict(d.pop("meta")) 95 96 _points = d.pop("points", UNSET) 97 points: list[EquityPoint] | Unset = UNSET 98 if _points is not UNSET: 99 points = [] 100 for points_item_data in _points: 101 points_item = EquityPoint.from_dict(points_item_data) 102 103 points.append(points_item) 104 105 timestamps = cast(list[int], d.pop("timestamps", UNSET)) 106 107 equities = cast(list[float], d.pop("equities", UNSET)) 108 109 url = d.pop("url", UNSET) 110 111 equity_curve_result = cls( 112 meta=meta, 113 points=points, 114 timestamps=timestamps, 115 equities=equities, 116 url=url, 117 ) 118 119 equity_curve_result.additional_properties = d 120 return equity_curve_result 121 122 @property 123 def additional_keys(self) -> list[str]: 124 return list(self.additional_properties.keys()) 125 126 def __getitem__(self, key: str) -> Any: 127 return self.additional_properties[key] 128 129 def __setitem__(self, key: str, value: Any) -> None: 130 self.additional_properties[key] = value 131 132 def __delitem__(self, key: str) -> None: 133 del self.additional_properties[key] 134 135 def __contains__(self, key: str) -> bool: 136 return key in self.additional_properties
An equity curve, shaped per meta.outMode: points when ARRAY, timestamps + equities (parallel arrays) when
SHORT. Used identically wherever a curve is returned — a plain backtest's inline equityCurve and a sweep row's
equityCurve are the same type. url is present instead of any points when the curve is served by pointer rather
than inline (a sweep row's top-N winners only): GET it separately to fetch this exact same shape with the points
populated.
Attributes:
meta (EquityCurveMeta): What the transform pipeline actually did, computed from the observed outcome — never a
copy of what was requested. Lets a caller detect a forced or no-op transform (e.g. a `resample` ceiling already
above the curve's size is a legal no-op, reported honestly as `resampled: false`).
points (list[EquityPoint] | Unset): Present when `meta.outMode` is `ARRAY` and the curve is inline (not a
pointer).
timestamps (list[int] | Unset): Present when `meta.outMode` is `SHORT` and the curve is inline (not a pointer).
equities (list[float] | Unset): Present when `meta.outMode` is `SHORT` and the curve is inline (not a pointer),
parallel to `timestamps` (same index, same point).
url (str | Unset): Present only for a sweep row's pointer curve. `GET` this to fetch the curve itself, in this
exact `{points|timestamps+equities, meta}` shape — `meta` there is the real, possibly size-guarded outcome; this
outer `meta` is a raw, untransformed preview from the moment the sweep selected this trial's curve, and the two
can legitimately differ. Example: /v1/backtest/binance/ticker/executeSweep/req-1/swp_test/runs/3/equityCurve.
28def __init__(self, meta, points=attr_dict['points'].default, timestamps=attr_dict['timestamps'].default, equities=attr_dict['equities'].default, url=attr_dict['url'].default): 29 self.meta = meta 30 self.points = points 31 self.timestamps = timestamps 32 self.equities = equities 33 self.url = url 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class EquityCurveResult.
50 def to_dict(self) -> dict[str, Any]: 51 meta = self.meta.to_dict() 52 53 points: list[dict[str, Any]] | Unset = UNSET 54 if not isinstance(self.points, Unset): 55 points = [] 56 for points_item_data in self.points: 57 points_item = points_item_data.to_dict() 58 points.append(points_item) 59 60 timestamps: list[int] | Unset = UNSET 61 if not isinstance(self.timestamps, Unset): 62 timestamps = self.timestamps 63 64 equities: list[float] | Unset = UNSET 65 if not isinstance(self.equities, Unset): 66 equities = self.equities 67 68 url = self.url 69 70 field_dict: dict[str, Any] = {} 71 field_dict.update(self.additional_properties) 72 field_dict.update( 73 { 74 "meta": meta, 75 } 76 ) 77 if points is not UNSET: 78 field_dict["points"] = points 79 if timestamps is not UNSET: 80 field_dict["timestamps"] = timestamps 81 if equities is not UNSET: 82 field_dict["equities"] = equities 83 if url is not UNSET: 84 field_dict["url"] = url 85 86 return field_dict
88 @classmethod 89 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 90 from ..models.equity_curve_meta import EquityCurveMeta 91 from ..models.equity_point import EquityPoint 92 93 d = dict(src_dict) 94 meta = EquityCurveMeta.from_dict(d.pop("meta")) 95 96 _points = d.pop("points", UNSET) 97 points: list[EquityPoint] | Unset = UNSET 98 if _points is not UNSET: 99 points = [] 100 for points_item_data in _points: 101 points_item = EquityPoint.from_dict(points_item_data) 102 103 points.append(points_item) 104 105 timestamps = cast(list[int], d.pop("timestamps", UNSET)) 106 107 equities = cast(list[float], d.pop("equities", UNSET)) 108 109 url = d.pop("url", UNSET) 110 111 equity_curve_result = cls( 112 meta=meta, 113 points=points, 114 timestamps=timestamps, 115 equities=equities, 116 url=url, 117 ) 118 119 equity_curve_result.additional_properties = d 120 return equity_curve_result
13@_attrs_define 14class EquityPoint: 15 """Single sample of the running equity at a yield event. 16 17 Attributes: 18 timestamp (int): Epoch milliseconds. The first point in an equity curve is anchored at the backtest `from`; 19 subsequent points carry the timestamp of each emitted yield. Example: 1700000000000. 20 equity (float): Running equity at this point (`initialCapital + cumulativePnl`). Example: 110.5. 21 """ 22 23 timestamp: int 24 equity: float 25 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 26 27 def to_dict(self) -> dict[str, Any]: 28 timestamp = self.timestamp 29 30 equity = self.equity 31 32 field_dict: dict[str, Any] = {} 33 field_dict.update(self.additional_properties) 34 field_dict.update( 35 { 36 "timestamp": timestamp, 37 "equity": equity, 38 } 39 ) 40 41 return field_dict 42 43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 d = dict(src_dict) 46 timestamp = d.pop("timestamp") 47 48 equity = d.pop("equity") 49 50 equity_point = cls( 51 timestamp=timestamp, 52 equity=equity, 53 ) 54 55 equity_point.additional_properties = d 56 return equity_point 57 58 @property 59 def additional_keys(self) -> list[str]: 60 return list(self.additional_properties.keys()) 61 62 def __getitem__(self, key: str) -> Any: 63 return self.additional_properties[key] 64 65 def __setitem__(self, key: str, value: Any) -> None: 66 self.additional_properties[key] = value 67 68 def __delitem__(self, key: str) -> None: 69 del self.additional_properties[key] 70 71 def __contains__(self, key: str) -> bool: 72 return key in self.additional_properties
Single sample of the running equity at a yield event.
Attributes:
timestamp (int): Epoch milliseconds. The first point in an equity curve is anchored at the backtest from;
subsequent points carry the timestamp of each emitted yield. Example: 1700000000000.
equity (float): Running equity at this point (initialCapital + cumulativePnl). Example: 110.5.
25def __init__(self, timestamp, equity): 26 self.timestamp = timestamp 27 self.equity = equity 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class EquityPoint.
43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 d = dict(src_dict) 46 timestamp = d.pop("timestamp") 47 48 equity = d.pop("equity") 49 50 equity_point = cls( 51 timestamp=timestamp, 52 equity=equity, 53 ) 54 55 equity_point.additional_properties = d 56 return equity_point
15@_attrs_define 16class Exchange: 17 """Exchange service provider 18 19 Attributes: 20 id (str): Unique identifier for the exchange Example: binance. 21 name (str): Name of the exchange Example: Binance. 22 description (str | Unset): Description of the exchange Example: Binance cryptocurrency exchange. 23 """ 24 25 id: str 26 name: str 27 description: str | Unset = UNSET 28 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 29 30 def to_dict(self) -> dict[str, Any]: 31 id = self.id 32 33 name = self.name 34 35 description = self.description 36 37 field_dict: dict[str, Any] = {} 38 field_dict.update(self.additional_properties) 39 field_dict.update( 40 { 41 "id": id, 42 "name": name, 43 } 44 ) 45 if description is not UNSET: 46 field_dict["description"] = description 47 48 return field_dict 49 50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 d = dict(src_dict) 53 id = d.pop("id") 54 55 name = d.pop("name") 56 57 description = d.pop("description", UNSET) 58 59 exchange = cls( 60 id=id, 61 name=name, 62 description=description, 63 ) 64 65 exchange.additional_properties = d 66 return exchange 67 68 @property 69 def additional_keys(self) -> list[str]: 70 return list(self.additional_properties.keys()) 71 72 def __getitem__(self, key: str) -> Any: 73 return self.additional_properties[key] 74 75 def __setitem__(self, key: str, value: Any) -> None: 76 self.additional_properties[key] = value 77 78 def __delitem__(self, key: str) -> None: 79 del self.additional_properties[key] 80 81 def __contains__(self, key: str) -> bool: 82 return key in self.additional_properties
Exchange service provider
Attributes: id (str): Unique identifier for the exchange Example: binance. name (str): Name of the exchange Example: Binance. description (str | Unset): Description of the exchange Example: Binance cryptocurrency exchange.
26def __init__(self, id, name, description=attr_dict['description'].default): 27 self.id = id 28 self.name = name 29 self.description = description 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class Exchange.
30 def to_dict(self) -> dict[str, Any]: 31 id = self.id 32 33 name = self.name 34 35 description = self.description 36 37 field_dict: dict[str, Any] = {} 38 field_dict.update(self.additional_properties) 39 field_dict.update( 40 { 41 "id": id, 42 "name": name, 43 } 44 ) 45 if description is not UNSET: 46 field_dict["description"] = description 47 48 return field_dict
50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 d = dict(src_dict) 53 id = d.pop("id") 54 55 name = d.pop("name") 56 57 description = d.pop("description", UNSET) 58 59 exchange = cls( 60 id=id, 61 name=name, 62 description=description, 63 ) 64 65 exchange.additional_properties = d 66 return exchange
19@_attrs_define 20class ExecuteBacktestBody: 21 """ 22 Attributes: 23 prepare_job_id (str): Job ID returned by `POST /prepare` (must be in `Completed` state) Example: 24 13RBLGQlPnfDjO6wyKSX8i. 25 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 26 always yields the same id, for every caller, whatever its formatting. See 27 `POST /strategy` for exactly which rewrites preserve it and which do not. 28 Example: 6bsh31ikwkuivhtgcoa6s4. 29 store_signals (bool | Unset): When true, the worker uploads emitted signals to object storage and the 30 response includes `signalsUrl` / `signalsId` fields. Defaults to false. 31 Default: False. 32 equity_curve (EquityCurveOptions | Unset): Requested equity-curve transform, applied server-side in a fixed 33 pipeline order: `resample` (point count) then `differential` (encoding) then `outMode` (JSON shape) — each stage 34 assumes the previous one already ran. A server-side size guard can still force a smaller/deflated shape above 35 its thresholds regardless of what is requested here — see `EquityCurveMeta` for what actually happened. 36 """ 37 38 prepare_job_id: str 39 strategy_id: str 40 store_signals: bool | Unset = False 41 equity_curve: EquityCurveOptions | Unset = UNSET 42 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 43 44 def to_dict(self) -> dict[str, Any]: 45 prepare_job_id = self.prepare_job_id 46 47 strategy_id = self.strategy_id 48 49 store_signals = self.store_signals 50 51 equity_curve: dict[str, Any] | Unset = UNSET 52 if not isinstance(self.equity_curve, Unset): 53 equity_curve = self.equity_curve.to_dict() 54 55 field_dict: dict[str, Any] = {} 56 field_dict.update(self.additional_properties) 57 field_dict.update( 58 { 59 "prepareJobId": prepare_job_id, 60 "strategyId": strategy_id, 61 } 62 ) 63 if store_signals is not UNSET: 64 field_dict["storeSignals"] = store_signals 65 if equity_curve is not UNSET: 66 field_dict["equityCurve"] = equity_curve 67 68 return field_dict 69 70 @classmethod 71 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 72 from ..models.equity_curve_options import EquityCurveOptions 73 74 d = dict(src_dict) 75 prepare_job_id = d.pop("prepareJobId") 76 77 strategy_id = d.pop("strategyId") 78 79 store_signals = d.pop("storeSignals", UNSET) 80 81 _equity_curve = d.pop("equityCurve", UNSET) 82 equity_curve: EquityCurveOptions | Unset 83 if isinstance(_equity_curve, Unset): 84 equity_curve = UNSET 85 else: 86 equity_curve = EquityCurveOptions.from_dict(_equity_curve) 87 88 execute_backtest_body = cls( 89 prepare_job_id=prepare_job_id, 90 strategy_id=strategy_id, 91 store_signals=store_signals, 92 equity_curve=equity_curve, 93 ) 94 95 execute_backtest_body.additional_properties = d 96 return execute_backtest_body 97 98 @property 99 def additional_keys(self) -> list[str]: 100 return list(self.additional_properties.keys()) 101 102 def __getitem__(self, key: str) -> Any: 103 return self.additional_properties[key] 104 105 def __setitem__(self, key: str, value: Any) -> None: 106 self.additional_properties[key] = value 107 108 def __delitem__(self, key: str) -> None: 109 del self.additional_properties[key] 110 111 def __contains__(self, key: str) -> bool: 112 return key in self.additional_properties
Attributes:
prepare_job_id (str): Job ID returned by POST /prepare (must be in Completed state) Example:
13RBLGQlPnfDjO6wyKSX8i.
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
POST /strategy for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
store_signals (bool | Unset): When true, the worker uploads emitted signals to object storage and the
response includes signalsUrl / signalsId fields. Defaults to false.
Default: False.
equity_curve (EquityCurveOptions | Unset): Requested equity-curve transform, applied server-side in a fixed
pipeline order: resample (point count) then differential (encoding) then outMode (JSON shape) — each stage
assumes the previous one already ran. A server-side size guard can still force a smaller/deflated shape above
its thresholds regardless of what is requested here — see EquityCurveMeta for what actually happened.
27def __init__(self, prepare_job_id, strategy_id, store_signals=attr_dict['store_signals'].default, equity_curve=attr_dict['equity_curve'].default): 28 self.prepare_job_id = prepare_job_id 29 self.strategy_id = strategy_id 30 self.store_signals = store_signals 31 self.equity_curve = equity_curve 32 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ExecuteBacktestBody.
44 def to_dict(self) -> dict[str, Any]: 45 prepare_job_id = self.prepare_job_id 46 47 strategy_id = self.strategy_id 48 49 store_signals = self.store_signals 50 51 equity_curve: dict[str, Any] | Unset = UNSET 52 if not isinstance(self.equity_curve, Unset): 53 equity_curve = self.equity_curve.to_dict() 54 55 field_dict: dict[str, Any] = {} 56 field_dict.update(self.additional_properties) 57 field_dict.update( 58 { 59 "prepareJobId": prepare_job_id, 60 "strategyId": strategy_id, 61 } 62 ) 63 if store_signals is not UNSET: 64 field_dict["storeSignals"] = store_signals 65 if equity_curve is not UNSET: 66 field_dict["equityCurve"] = equity_curve 67 68 return field_dict
70 @classmethod 71 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 72 from ..models.equity_curve_options import EquityCurveOptions 73 74 d = dict(src_dict) 75 prepare_job_id = d.pop("prepareJobId") 76 77 strategy_id = d.pop("strategyId") 78 79 store_signals = d.pop("storeSignals", UNSET) 80 81 _equity_curve = d.pop("equityCurve", UNSET) 82 equity_curve: EquityCurveOptions | Unset 83 if isinstance(_equity_curve, Unset): 84 equity_curve = UNSET 85 else: 86 equity_curve = EquityCurveOptions.from_dict(_equity_curve) 87 88 execute_backtest_body = cls( 89 prepare_job_id=prepare_job_id, 90 strategy_id=strategy_id, 91 store_signals=store_signals, 92 equity_curve=equity_curve, 93 ) 94 95 execute_backtest_body.additional_properties = d 96 return execute_backtest_body
19@_attrs_define 20class ExecuteSweepAccepted: 21 """ 22 Attributes: 23 sweep_id (str): Example: swp_95e47a7f0966ce11. 24 request_id (str): 25 total_runs (int): 26 shards (int): 27 seed (int): Effective seed used to expand the sweep. 28 queued (bool): False when an identical sweep already exists and was not enqueued again. 29 walk_forward (WalkForwardAccepted | Unset): Echo of the accepted walk-forward configuration, present only when 30 the submit carried one. `inSamplePct` is the resolved value, so a request that omitted it can see what it got. 31 """ 32 33 sweep_id: str 34 request_id: str 35 total_runs: int 36 shards: int 37 seed: int 38 queued: bool 39 walk_forward: WalkForwardAccepted | Unset = UNSET 40 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 41 42 def to_dict(self) -> dict[str, Any]: 43 sweep_id = self.sweep_id 44 45 request_id = self.request_id 46 47 total_runs = self.total_runs 48 49 shards = self.shards 50 51 seed = self.seed 52 53 queued = self.queued 54 55 walk_forward: dict[str, Any] | Unset = UNSET 56 if not isinstance(self.walk_forward, Unset): 57 walk_forward = self.walk_forward.to_dict() 58 59 field_dict: dict[str, Any] = {} 60 field_dict.update(self.additional_properties) 61 field_dict.update( 62 { 63 "sweepId": sweep_id, 64 "requestId": request_id, 65 "totalRuns": total_runs, 66 "shards": shards, 67 "seed": seed, 68 "queued": queued, 69 } 70 ) 71 if walk_forward is not UNSET: 72 field_dict["walkForward"] = walk_forward 73 74 return field_dict 75 76 @classmethod 77 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 78 from ..models.walk_forward_accepted import WalkForwardAccepted 79 80 d = dict(src_dict) 81 sweep_id = d.pop("sweepId") 82 83 request_id = d.pop("requestId") 84 85 total_runs = d.pop("totalRuns") 86 87 shards = d.pop("shards") 88 89 seed = d.pop("seed") 90 91 queued = d.pop("queued") 92 93 _walk_forward = d.pop("walkForward", UNSET) 94 walk_forward: WalkForwardAccepted | Unset 95 if isinstance(_walk_forward, Unset): 96 walk_forward = UNSET 97 else: 98 walk_forward = WalkForwardAccepted.from_dict(_walk_forward) 99 100 execute_sweep_accepted = cls( 101 sweep_id=sweep_id, 102 request_id=request_id, 103 total_runs=total_runs, 104 shards=shards, 105 seed=seed, 106 queued=queued, 107 walk_forward=walk_forward, 108 ) 109 110 execute_sweep_accepted.additional_properties = d 111 return execute_sweep_accepted 112 113 @property 114 def additional_keys(self) -> list[str]: 115 return list(self.additional_properties.keys()) 116 117 def __getitem__(self, key: str) -> Any: 118 return self.additional_properties[key] 119 120 def __setitem__(self, key: str, value: Any) -> None: 121 self.additional_properties[key] = value 122 123 def __delitem__(self, key: str) -> None: 124 del self.additional_properties[key] 125 126 def __contains__(self, key: str) -> bool: 127 return key in self.additional_properties
Attributes:
sweep_id (str): Example: swp_95e47a7f0966ce11.
request_id (str):
total_runs (int):
shards (int):
seed (int): Effective seed used to expand the sweep.
queued (bool): False when an identical sweep already exists and was not enqueued again.
walk_forward (WalkForwardAccepted | Unset): Echo of the accepted walk-forward configuration, present only when
the submit carried one. inSamplePct is the resolved value, so a request that omitted it can see what it got.
30def __init__(self, sweep_id, request_id, total_runs, shards, seed, queued, walk_forward=attr_dict['walk_forward'].default): 31 self.sweep_id = sweep_id 32 self.request_id = request_id 33 self.total_runs = total_runs 34 self.shards = shards 35 self.seed = seed 36 self.queued = queued 37 self.walk_forward = walk_forward 38 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ExecuteSweepAccepted.
42 def to_dict(self) -> dict[str, Any]: 43 sweep_id = self.sweep_id 44 45 request_id = self.request_id 46 47 total_runs = self.total_runs 48 49 shards = self.shards 50 51 seed = self.seed 52 53 queued = self.queued 54 55 walk_forward: dict[str, Any] | Unset = UNSET 56 if not isinstance(self.walk_forward, Unset): 57 walk_forward = self.walk_forward.to_dict() 58 59 field_dict: dict[str, Any] = {} 60 field_dict.update(self.additional_properties) 61 field_dict.update( 62 { 63 "sweepId": sweep_id, 64 "requestId": request_id, 65 "totalRuns": total_runs, 66 "shards": shards, 67 "seed": seed, 68 "queued": queued, 69 } 70 ) 71 if walk_forward is not UNSET: 72 field_dict["walkForward"] = walk_forward 73 74 return field_dict
76 @classmethod 77 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 78 from ..models.walk_forward_accepted import WalkForwardAccepted 79 80 d = dict(src_dict) 81 sweep_id = d.pop("sweepId") 82 83 request_id = d.pop("requestId") 84 85 total_runs = d.pop("totalRuns") 86 87 shards = d.pop("shards") 88 89 seed = d.pop("seed") 90 91 queued = d.pop("queued") 92 93 _walk_forward = d.pop("walkForward", UNSET) 94 walk_forward: WalkForwardAccepted | Unset 95 if isinstance(_walk_forward, Unset): 96 walk_forward = UNSET 97 else: 98 walk_forward = WalkForwardAccepted.from_dict(_walk_forward) 99 100 execute_sweep_accepted = cls( 101 sweep_id=sweep_id, 102 request_id=request_id, 103 total_runs=total_runs, 104 shards=shards, 105 seed=seed, 106 queued=queued, 107 walk_forward=walk_forward, 108 ) 109 110 execute_sweep_accepted.additional_properties = d 111 return execute_sweep_accepted
22@_attrs_define 23class ExecuteSweepRequest: 24 """ 25 Attributes: 26 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 27 always yields the same id, for every caller, whatever its formatting. See 28 `POST /strategy` for exactly which rewrites preserve it and which do not. 29 Example: 6bsh31ikwkuivhtgcoa6s4. 30 sweep (SweepSpecRequest): Example: {'sampler': 'lhs', 'seed': 487221, 'samples': 100, 'objective': 'sharpe', 31 'params': {'rsiPeriod': {'from': 7, 'to': 28, 'step': 1}, 'useTrendFilter': {'values': [True, False]}}}. 32 base_config (SweepBaseConfig | Unset): 33 store_signals (bool | Unset): Store signals for every trial. Keep false for normal sweeps. Default: False. 34 shards (int | Unset): Requested horizontal shard count; 0 or omitted selects automatically. Default: 0. 35 min_trade_floor (int | Unset): Trials below this trade count are flagged but remain in the results. Default: 30. 36 walk_forward (WalkForwardRequest | Unset): Opt in to walk-forward validation. Present, the sweep runs as F 37 sequential folds and the result gains a `walkForward` section; absent, nothing about the sweep changes. Two 38 requests that differ only in this block are two different sweeps and do not deduplicate against each other. 39 equity_curve (EquityCurveRequest | Unset): Selection (`mode`/`n`/`maxPct`) plus the transform preference 40 (`resample`/`differential`/`outMode`) applied by `GET .../equityCurve` whenever ITS OWN query params are absent, 41 for a curve this sweep retained. The transform half never affects retention or `sweepId` — a caller can always 42 override it per-request at read time regardless of what was submitted here. 43 """ 44 45 strategy_id: str 46 sweep: SweepSpecRequest 47 base_config: SweepBaseConfig | Unset = UNSET 48 store_signals: bool | Unset = False 49 shards: int | Unset = 0 50 min_trade_floor: int | Unset = 30 51 walk_forward: WalkForwardRequest | Unset = UNSET 52 equity_curve: EquityCurveRequest | Unset = UNSET 53 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 54 55 def to_dict(self) -> dict[str, Any]: 56 strategy_id = self.strategy_id 57 58 sweep = self.sweep.to_dict() 59 60 base_config: dict[str, Any] | Unset = UNSET 61 if not isinstance(self.base_config, Unset): 62 base_config = self.base_config.to_dict() 63 64 store_signals = self.store_signals 65 66 shards = self.shards 67 68 min_trade_floor = self.min_trade_floor 69 70 walk_forward: dict[str, Any] | Unset = UNSET 71 if not isinstance(self.walk_forward, Unset): 72 walk_forward = self.walk_forward.to_dict() 73 74 equity_curve: dict[str, Any] | Unset = UNSET 75 if not isinstance(self.equity_curve, Unset): 76 equity_curve = self.equity_curve.to_dict() 77 78 field_dict: dict[str, Any] = {} 79 field_dict.update(self.additional_properties) 80 field_dict.update( 81 { 82 "strategyId": strategy_id, 83 "sweep": sweep, 84 } 85 ) 86 if base_config is not UNSET: 87 field_dict["baseConfig"] = base_config 88 if store_signals is not UNSET: 89 field_dict["storeSignals"] = store_signals 90 if shards is not UNSET: 91 field_dict["shards"] = shards 92 if min_trade_floor is not UNSET: 93 field_dict["minTradeFloor"] = min_trade_floor 94 if walk_forward is not UNSET: 95 field_dict["walkForward"] = walk_forward 96 if equity_curve is not UNSET: 97 field_dict["equityCurve"] = equity_curve 98 99 return field_dict 100 101 @classmethod 102 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 103 from ..models.equity_curve_request import EquityCurveRequest 104 from ..models.sweep_base_config import SweepBaseConfig 105 from ..models.sweep_spec_request import SweepSpecRequest 106 from ..models.walk_forward_request import WalkForwardRequest 107 108 d = dict(src_dict) 109 strategy_id = d.pop("strategyId") 110 111 sweep = SweepSpecRequest.from_dict(d.pop("sweep")) 112 113 _base_config = d.pop("baseConfig", UNSET) 114 base_config: SweepBaseConfig | Unset 115 if isinstance(_base_config, Unset): 116 base_config = UNSET 117 else: 118 base_config = SweepBaseConfig.from_dict(_base_config) 119 120 store_signals = d.pop("storeSignals", UNSET) 121 122 shards = d.pop("shards", UNSET) 123 124 min_trade_floor = d.pop("minTradeFloor", UNSET) 125 126 _walk_forward = d.pop("walkForward", UNSET) 127 walk_forward: WalkForwardRequest | Unset 128 if isinstance(_walk_forward, Unset): 129 walk_forward = UNSET 130 else: 131 walk_forward = WalkForwardRequest.from_dict(_walk_forward) 132 133 _equity_curve = d.pop("equityCurve", UNSET) 134 equity_curve: EquityCurveRequest | Unset 135 if isinstance(_equity_curve, Unset): 136 equity_curve = UNSET 137 else: 138 equity_curve = EquityCurveRequest.from_dict(_equity_curve) 139 140 execute_sweep_request = cls( 141 strategy_id=strategy_id, 142 sweep=sweep, 143 base_config=base_config, 144 store_signals=store_signals, 145 shards=shards, 146 min_trade_floor=min_trade_floor, 147 walk_forward=walk_forward, 148 equity_curve=equity_curve, 149 ) 150 151 execute_sweep_request.additional_properties = d 152 return execute_sweep_request 153 154 @property 155 def additional_keys(self) -> list[str]: 156 return list(self.additional_properties.keys()) 157 158 def __getitem__(self, key: str) -> Any: 159 return self.additional_properties[key] 160 161 def __setitem__(self, key: str, value: Any) -> None: 162 self.additional_properties[key] = value 163 164 def __delitem__(self, key: str) -> None: 165 del self.additional_properties[key] 166 167 def __contains__(self, key: str) -> bool: 168 return key in self.additional_properties
Attributes:
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
POST /strategy for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
sweep (SweepSpecRequest): Example: {'sampler': 'lhs', 'seed': 487221, 'samples': 100, 'objective': 'sharpe',
'params': {'rsiPeriod': {'from': 7, 'to': 28, 'step': 1}, 'useTrendFilter': {'values': [True, False]}}}.
base_config (SweepBaseConfig | Unset):
store_signals (bool | Unset): Store signals for every trial. Keep false for normal sweeps. Default: False.
shards (int | Unset): Requested horizontal shard count; 0 or omitted selects automatically. Default: 0.
min_trade_floor (int | Unset): Trials below this trade count are flagged but remain in the results. Default: 30.
walk_forward (WalkForwardRequest | Unset): Opt in to walk-forward validation. Present, the sweep runs as F
sequential folds and the result gains a walkForward section; absent, nothing about the sweep changes. Two
requests that differ only in this block are two different sweeps and do not deduplicate against each other.
equity_curve (EquityCurveRequest | Unset): Selection (mode/n/maxPct) plus the transform preference
(resample/differential/outMode) applied by GET .../equityCurve whenever ITS OWN query params are absent,
for a curve this sweep retained. The transform half never affects retention or sweepId — a caller can always
override it per-request at read time regardless of what was submitted here.
31def __init__(self, strategy_id, sweep, base_config=attr_dict['base_config'].default, store_signals=attr_dict['store_signals'].default, shards=attr_dict['shards'].default, min_trade_floor=attr_dict['min_trade_floor'].default, walk_forward=attr_dict['walk_forward'].default, equity_curve=attr_dict['equity_curve'].default): 32 self.strategy_id = strategy_id 33 self.sweep = sweep 34 self.base_config = base_config 35 self.store_signals = store_signals 36 self.shards = shards 37 self.min_trade_floor = min_trade_floor 38 self.walk_forward = walk_forward 39 self.equity_curve = equity_curve 40 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ExecuteSweepRequest.
55 def to_dict(self) -> dict[str, Any]: 56 strategy_id = self.strategy_id 57 58 sweep = self.sweep.to_dict() 59 60 base_config: dict[str, Any] | Unset = UNSET 61 if not isinstance(self.base_config, Unset): 62 base_config = self.base_config.to_dict() 63 64 store_signals = self.store_signals 65 66 shards = self.shards 67 68 min_trade_floor = self.min_trade_floor 69 70 walk_forward: dict[str, Any] | Unset = UNSET 71 if not isinstance(self.walk_forward, Unset): 72 walk_forward = self.walk_forward.to_dict() 73 74 equity_curve: dict[str, Any] | Unset = UNSET 75 if not isinstance(self.equity_curve, Unset): 76 equity_curve = self.equity_curve.to_dict() 77 78 field_dict: dict[str, Any] = {} 79 field_dict.update(self.additional_properties) 80 field_dict.update( 81 { 82 "strategyId": strategy_id, 83 "sweep": sweep, 84 } 85 ) 86 if base_config is not UNSET: 87 field_dict["baseConfig"] = base_config 88 if store_signals is not UNSET: 89 field_dict["storeSignals"] = store_signals 90 if shards is not UNSET: 91 field_dict["shards"] = shards 92 if min_trade_floor is not UNSET: 93 field_dict["minTradeFloor"] = min_trade_floor 94 if walk_forward is not UNSET: 95 field_dict["walkForward"] = walk_forward 96 if equity_curve is not UNSET: 97 field_dict["equityCurve"] = equity_curve 98 99 return field_dict
101 @classmethod 102 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 103 from ..models.equity_curve_request import EquityCurveRequest 104 from ..models.sweep_base_config import SweepBaseConfig 105 from ..models.sweep_spec_request import SweepSpecRequest 106 from ..models.walk_forward_request import WalkForwardRequest 107 108 d = dict(src_dict) 109 strategy_id = d.pop("strategyId") 110 111 sweep = SweepSpecRequest.from_dict(d.pop("sweep")) 112 113 _base_config = d.pop("baseConfig", UNSET) 114 base_config: SweepBaseConfig | Unset 115 if isinstance(_base_config, Unset): 116 base_config = UNSET 117 else: 118 base_config = SweepBaseConfig.from_dict(_base_config) 119 120 store_signals = d.pop("storeSignals", UNSET) 121 122 shards = d.pop("shards", UNSET) 123 124 min_trade_floor = d.pop("minTradeFloor", UNSET) 125 126 _walk_forward = d.pop("walkForward", UNSET) 127 walk_forward: WalkForwardRequest | Unset 128 if isinstance(_walk_forward, Unset): 129 walk_forward = UNSET 130 else: 131 walk_forward = WalkForwardRequest.from_dict(_walk_forward) 132 133 _equity_curve = d.pop("equityCurve", UNSET) 134 equity_curve: EquityCurveRequest | Unset 135 if isinstance(_equity_curve, Unset): 136 equity_curve = UNSET 137 else: 138 equity_curve = EquityCurveRequest.from_dict(_equity_curve) 139 140 execute_sweep_request = cls( 141 strategy_id=strategy_id, 142 sweep=sweep, 143 base_config=base_config, 144 store_signals=store_signals, 145 shards=shards, 146 min_trade_floor=min_trade_floor, 147 walk_forward=walk_forward, 148 equity_curve=equity_curve, 149 ) 150 151 execute_sweep_request.additional_properties = d 152 return execute_sweep_request
26@_attrs_define 27class ExecuteSweepResult: 28 """ 29 Attributes: 30 sweep_id (str): 31 status (ExecuteSweepResultStatus): The sweep's own status vocabulary — not the same set `state.status` below 32 uses. See `state` for why. 33 objective (ExecuteSweepResultObjective): 34 order (ExecuteSweepResultOrder): 35 progress (SweepProgress): How far along a sweep is, and — when the sweep is still running — enough to tell a 36 healthy one from a stuck one. The counts partition the shards (or, for a walk-forward sweep, the folds): every 37 unit is either finished, failed, waiting to be retried, or not yet started. 38 leaderboard_size (int): Total result rows currently available. 39 truncated (bool): True only when the ranked view exceeds its display limit. 40 leaderboard (list[SweepRunRow]): 41 state (JobState): Information about a single job 42 ranking (ExecuteSweepResultRanking | Unset): Which ordering was actually applied, which is not always the one 43 requested: a sweep with no stored parameter grid cannot be plateau-ranked and falls back to `raw`. Always `raw` 44 when `order=natural`. 45 pbo (float | Unset): Probability of backtest overfitting for the sweep as a whole, by combinatorially symmetric 46 cross-validation: how often the configuration that won in-sample lands below median out-of-sample. Above ~0.5 47 the sweep is selecting noise, whatever its top row says. Computed once when the last shard finishes, so it is 48 absent while the sweep is still running and on sweeps too small for the statistic to mean anything. 49 pbo_splits (int | Unset): How many train/test splits the `pbo` figure was averaged over. 50 fail_reason (str | Unset): Why the sweep produced less than it should have — the cause reported by the **first** 51 shard to fail, not a list. It is what turns an inscrutable empty leaderboard into an answer: a sweep can come 52 back `PARTIAL` with `done: 0` because the strategy could not be loaded at all, and without this the response 53 says only that nothing finished. 54 First failure wins and later ones are not recorded, so on a sweep where several shards failed for different 55 reasons this names one of them rather than all. Absent when no shard reported a cause, which is the normal case 56 for a healthy sweep — read it together with `progress.failedShards` rather than as a count of anything. Example: 57 Failed to load/configure strategy. 58 walk_forward (WalkForwardResult | Unset): Present only on a sweep submitted with `walkForward`, and present from 59 acceptance onward — its presence, not its contents, is what identifies a walk-forward sweep. `completedFolds` is 60 0 while the first fold is still running. 61 """ 62 63 sweep_id: str 64 status: ExecuteSweepResultStatus 65 objective: ExecuteSweepResultObjective 66 order: ExecuteSweepResultOrder 67 progress: SweepProgress 68 leaderboard_size: int 69 truncated: bool 70 leaderboard: list[SweepRunRow] 71 state: JobState 72 ranking: ExecuteSweepResultRanking | Unset = UNSET 73 pbo: float | Unset = UNSET 74 pbo_splits: int | Unset = UNSET 75 fail_reason: str | Unset = UNSET 76 walk_forward: WalkForwardResult | Unset = UNSET 77 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 78 79 def to_dict(self) -> dict[str, Any]: 80 sweep_id = self.sweep_id 81 82 status = self.status.value 83 84 objective = self.objective.value 85 86 order = self.order.value 87 88 progress = self.progress.to_dict() 89 90 leaderboard_size = self.leaderboard_size 91 92 truncated = self.truncated 93 94 leaderboard = [] 95 for leaderboard_item_data in self.leaderboard: 96 leaderboard_item = leaderboard_item_data.to_dict() 97 leaderboard.append(leaderboard_item) 98 99 state = self.state.to_dict() 100 101 ranking: str | Unset = UNSET 102 if not isinstance(self.ranking, Unset): 103 ranking = self.ranking.value 104 105 pbo = self.pbo 106 107 pbo_splits = self.pbo_splits 108 109 fail_reason = self.fail_reason 110 111 walk_forward: dict[str, Any] | Unset = UNSET 112 if not isinstance(self.walk_forward, Unset): 113 walk_forward = self.walk_forward.to_dict() 114 115 field_dict: dict[str, Any] = {} 116 field_dict.update(self.additional_properties) 117 field_dict.update( 118 { 119 "sweepId": sweep_id, 120 "status": status, 121 "objective": objective, 122 "order": order, 123 "progress": progress, 124 "leaderboardSize": leaderboard_size, 125 "truncated": truncated, 126 "leaderboard": leaderboard, 127 "state": state, 128 } 129 ) 130 if ranking is not UNSET: 131 field_dict["ranking"] = ranking 132 if pbo is not UNSET: 133 field_dict["pbo"] = pbo 134 if pbo_splits is not UNSET: 135 field_dict["pboSplits"] = pbo_splits 136 if fail_reason is not UNSET: 137 field_dict["failReason"] = fail_reason 138 if walk_forward is not UNSET: 139 field_dict["walkForward"] = walk_forward 140 141 return field_dict 142 143 @classmethod 144 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 145 from ..models.job_state import JobState 146 from ..models.sweep_progress import SweepProgress 147 from ..models.sweep_run_row import SweepRunRow 148 from ..models.walk_forward_result import WalkForwardResult 149 150 d = dict(src_dict) 151 sweep_id = d.pop("sweepId") 152 153 status = ExecuteSweepResultStatus(d.pop("status")) 154 155 objective = ExecuteSweepResultObjective(d.pop("objective")) 156 157 order = ExecuteSweepResultOrder(d.pop("order")) 158 159 progress = SweepProgress.from_dict(d.pop("progress")) 160 161 leaderboard_size = d.pop("leaderboardSize") 162 163 truncated = d.pop("truncated") 164 165 leaderboard = [] 166 _leaderboard = d.pop("leaderboard") 167 for leaderboard_item_data in _leaderboard: 168 leaderboard_item = SweepRunRow.from_dict(leaderboard_item_data) 169 170 leaderboard.append(leaderboard_item) 171 172 state = JobState.from_dict(d.pop("state")) 173 174 _ranking = d.pop("ranking", UNSET) 175 ranking: ExecuteSweepResultRanking | Unset 176 if isinstance(_ranking, Unset): 177 ranking = UNSET 178 else: 179 ranking = ExecuteSweepResultRanking(_ranking) 180 181 pbo = d.pop("pbo", UNSET) 182 183 pbo_splits = d.pop("pboSplits", UNSET) 184 185 fail_reason = d.pop("failReason", UNSET) 186 187 _walk_forward = d.pop("walkForward", UNSET) 188 walk_forward: WalkForwardResult | Unset 189 if isinstance(_walk_forward, Unset): 190 walk_forward = UNSET 191 else: 192 walk_forward = WalkForwardResult.from_dict(_walk_forward) 193 194 execute_sweep_result = cls( 195 sweep_id=sweep_id, 196 status=status, 197 objective=objective, 198 order=order, 199 progress=progress, 200 leaderboard_size=leaderboard_size, 201 truncated=truncated, 202 leaderboard=leaderboard, 203 state=state, 204 ranking=ranking, 205 pbo=pbo, 206 pbo_splits=pbo_splits, 207 fail_reason=fail_reason, 208 walk_forward=walk_forward, 209 ) 210 211 execute_sweep_result.additional_properties = d 212 return execute_sweep_result 213 214 @property 215 def additional_keys(self) -> list[str]: 216 return list(self.additional_properties.keys()) 217 218 def __getitem__(self, key: str) -> Any: 219 return self.additional_properties[key] 220 221 def __setitem__(self, key: str, value: Any) -> None: 222 self.additional_properties[key] = value 223 224 def __delitem__(self, key: str) -> None: 225 del self.additional_properties[key] 226 227 def __contains__(self, key: str) -> bool: 228 return key in self.additional_properties
Attributes:
sweep_id (str):
status (ExecuteSweepResultStatus): The sweep's own status vocabulary — not the same set state.status below
uses. See state for why.
objective (ExecuteSweepResultObjective):
order (ExecuteSweepResultOrder):
progress (SweepProgress): How far along a sweep is, and — when the sweep is still running — enough to tell a
healthy one from a stuck one. The counts partition the shards (or, for a walk-forward sweep, the folds): every
unit is either finished, failed, waiting to be retried, or not yet started.
leaderboard_size (int): Total result rows currently available.
truncated (bool): True only when the ranked view exceeds its display limit.
leaderboard (list[SweepRunRow]):
state (JobState): Information about a single job
ranking (ExecuteSweepResultRanking | Unset): Which ordering was actually applied, which is not always the one
requested: a sweep with no stored parameter grid cannot be plateau-ranked and falls back to raw. Always raw
when order=natural.
pbo (float | Unset): Probability of backtest overfitting for the sweep as a whole, by combinatorially symmetric
cross-validation: how often the configuration that won in-sample lands below median out-of-sample. Above ~0.5
the sweep is selecting noise, whatever its top row says. Computed once when the last shard finishes, so it is
absent while the sweep is still running and on sweeps too small for the statistic to mean anything.
pbo_splits (int | Unset): How many train/test splits the pbo figure was averaged over.
fail_reason (str | Unset): Why the sweep produced less than it should have — the cause reported by the first
shard to fail, not a list. It is what turns an inscrutable empty leaderboard into an answer: a sweep can come
back PARTIAL with done: 0 because the strategy could not be loaded at all, and without this the response
says only that nothing finished.
First failure wins and later ones are not recorded, so on a sweep where several shards failed for different
reasons this names one of them rather than all. Absent when no shard reported a cause, which is the normal case
for a healthy sweep — read it together with progress.failedShards rather than as a count of anything. Example:
Failed to load/configure strategy.
walk_forward (WalkForwardResult | Unset): Present only on a sweep submitted with walkForward, and present from
acceptance onward — its presence, not its contents, is what identifies a walk-forward sweep. completedFolds is
0 while the first fold is still running.
37def __init__(self, sweep_id, status, objective, order, progress, leaderboard_size, truncated, leaderboard, state, ranking=attr_dict['ranking'].default, pbo=attr_dict['pbo'].default, pbo_splits=attr_dict['pbo_splits'].default, fail_reason=attr_dict['fail_reason'].default, walk_forward=attr_dict['walk_forward'].default): 38 self.sweep_id = sweep_id 39 self.status = status 40 self.objective = objective 41 self.order = order 42 self.progress = progress 43 self.leaderboard_size = leaderboard_size 44 self.truncated = truncated 45 self.leaderboard = leaderboard 46 self.state = state 47 self.ranking = ranking 48 self.pbo = pbo 49 self.pbo_splits = pbo_splits 50 self.fail_reason = fail_reason 51 self.walk_forward = walk_forward 52 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ExecuteSweepResult.
79 def to_dict(self) -> dict[str, Any]: 80 sweep_id = self.sweep_id 81 82 status = self.status.value 83 84 objective = self.objective.value 85 86 order = self.order.value 87 88 progress = self.progress.to_dict() 89 90 leaderboard_size = self.leaderboard_size 91 92 truncated = self.truncated 93 94 leaderboard = [] 95 for leaderboard_item_data in self.leaderboard: 96 leaderboard_item = leaderboard_item_data.to_dict() 97 leaderboard.append(leaderboard_item) 98 99 state = self.state.to_dict() 100 101 ranking: str | Unset = UNSET 102 if not isinstance(self.ranking, Unset): 103 ranking = self.ranking.value 104 105 pbo = self.pbo 106 107 pbo_splits = self.pbo_splits 108 109 fail_reason = self.fail_reason 110 111 walk_forward: dict[str, Any] | Unset = UNSET 112 if not isinstance(self.walk_forward, Unset): 113 walk_forward = self.walk_forward.to_dict() 114 115 field_dict: dict[str, Any] = {} 116 field_dict.update(self.additional_properties) 117 field_dict.update( 118 { 119 "sweepId": sweep_id, 120 "status": status, 121 "objective": objective, 122 "order": order, 123 "progress": progress, 124 "leaderboardSize": leaderboard_size, 125 "truncated": truncated, 126 "leaderboard": leaderboard, 127 "state": state, 128 } 129 ) 130 if ranking is not UNSET: 131 field_dict["ranking"] = ranking 132 if pbo is not UNSET: 133 field_dict["pbo"] = pbo 134 if pbo_splits is not UNSET: 135 field_dict["pboSplits"] = pbo_splits 136 if fail_reason is not UNSET: 137 field_dict["failReason"] = fail_reason 138 if walk_forward is not UNSET: 139 field_dict["walkForward"] = walk_forward 140 141 return field_dict
143 @classmethod 144 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 145 from ..models.job_state import JobState 146 from ..models.sweep_progress import SweepProgress 147 from ..models.sweep_run_row import SweepRunRow 148 from ..models.walk_forward_result import WalkForwardResult 149 150 d = dict(src_dict) 151 sweep_id = d.pop("sweepId") 152 153 status = ExecuteSweepResultStatus(d.pop("status")) 154 155 objective = ExecuteSweepResultObjective(d.pop("objective")) 156 157 order = ExecuteSweepResultOrder(d.pop("order")) 158 159 progress = SweepProgress.from_dict(d.pop("progress")) 160 161 leaderboard_size = d.pop("leaderboardSize") 162 163 truncated = d.pop("truncated") 164 165 leaderboard = [] 166 _leaderboard = d.pop("leaderboard") 167 for leaderboard_item_data in _leaderboard: 168 leaderboard_item = SweepRunRow.from_dict(leaderboard_item_data) 169 170 leaderboard.append(leaderboard_item) 171 172 state = JobState.from_dict(d.pop("state")) 173 174 _ranking = d.pop("ranking", UNSET) 175 ranking: ExecuteSweepResultRanking | Unset 176 if isinstance(_ranking, Unset): 177 ranking = UNSET 178 else: 179 ranking = ExecuteSweepResultRanking(_ranking) 180 181 pbo = d.pop("pbo", UNSET) 182 183 pbo_splits = d.pop("pboSplits", UNSET) 184 185 fail_reason = d.pop("failReason", UNSET) 186 187 _walk_forward = d.pop("walkForward", UNSET) 188 walk_forward: WalkForwardResult | Unset 189 if isinstance(_walk_forward, Unset): 190 walk_forward = UNSET 191 else: 192 walk_forward = WalkForwardResult.from_dict(_walk_forward) 193 194 execute_sweep_result = cls( 195 sweep_id=sweep_id, 196 status=status, 197 objective=objective, 198 order=order, 199 progress=progress, 200 leaderboard_size=leaderboard_size, 201 truncated=truncated, 202 leaderboard=leaderboard, 203 state=state, 204 ranking=ranking, 205 pbo=pbo, 206 pbo_splits=pbo_splits, 207 fail_reason=fail_reason, 208 walk_forward=walk_forward, 209 ) 210 211 execute_sweep_result.additional_properties = d 212 return execute_sweep_result
5class ExecuteSweepResultObjective(str, Enum): 6 MAXDD = "maxdd" 7 PNL = "pnl" 8 SHARPE = "sharpe" 9 SORTINO = "sortino" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class ExecuteSweepResultOrder(str, Enum): 6 NATURAL = "natural" 7 RANKED = "ranked" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class ExecuteSweepResultRanking(str, Enum): 6 PLATEAU = "plateau" 7 RAW = "raw" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class ExecuteSweepResultStatus(str, Enum): 6 CANCELLED = "CANCELLED" 7 COMPLETED = "COMPLETED" 8 PARTIAL = "PARTIAL" 9 RUNNING = "RUNNING" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
13@_attrs_define 14class FinalizeDatasetUploadResponse202: 15 """ 16 Attributes: 17 job_id (str): 18 """ 19 20 job_id: str 21 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 22 23 def to_dict(self) -> dict[str, Any]: 24 job_id = self.job_id 25 26 field_dict: dict[str, Any] = {} 27 field_dict.update(self.additional_properties) 28 field_dict.update( 29 { 30 "jobId": job_id, 31 } 32 ) 33 34 return field_dict 35 36 @classmethod 37 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 38 d = dict(src_dict) 39 job_id = d.pop("jobId") 40 41 finalize_dataset_upload_response_202 = cls( 42 job_id=job_id, 43 ) 44 45 finalize_dataset_upload_response_202.additional_properties = d 46 return finalize_dataset_upload_response_202 47 48 @property 49 def additional_keys(self) -> list[str]: 50 return list(self.additional_properties.keys()) 51 52 def __getitem__(self, key: str) -> Any: 53 return self.additional_properties[key] 54 55 def __setitem__(self, key: str, value: Any) -> None: 56 self.additional_properties[key] = value 57 58 def __delitem__(self, key: str) -> None: 59 del self.additional_properties[key] 60 61 def __contains__(self, key: str) -> bool: 62 return key in self.additional_properties
Attributes: job_id (str):
24def __init__(self, job_id): 25 self.job_id = job_id 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class FinalizeDatasetUploadResponse202.
36 @classmethod 37 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 38 d = dict(src_dict) 39 job_id = d.pop("jobId") 40 41 finalize_dataset_upload_response_202 = cls( 42 job_id=job_id, 43 ) 44 45 finalize_dataset_upload_response_202.additional_properties = d 46 return finalize_dataset_upload_response_202
12@_attrs_define 13class GetBacktestResultResponse202: 14 """ """ 15 16 def to_dict(self) -> dict[str, Any]: 17 18 field_dict: dict[str, Any] = {} 19 20 return field_dict 21 22 @classmethod 23 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 24 get_backtest_result_response_202 = cls() 25 26 return get_backtest_result_response_202
13@_attrs_define 14class GetStrategyCodeResponse200: 15 """ 16 Attributes: 17 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 18 always yields the same id, for every caller, whatever its formatting. See 19 `POST /strategy` for exactly which rewrites preserve it and which do not. 20 Example: 6bsh31ikwkuivhtgcoa6s4. 21 code (str): Raw strategy Java source code, exactly as registered. 22 """ 23 24 strategy_id: str 25 code: str 26 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 27 28 def to_dict(self) -> dict[str, Any]: 29 strategy_id = self.strategy_id 30 31 code = self.code 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "strategyId": strategy_id, 38 "code": code, 39 } 40 ) 41 42 return field_dict 43 44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 strategy_id = d.pop("strategyId") 48 49 code = d.pop("code") 50 51 get_strategy_code_response_200 = cls( 52 strategy_id=strategy_id, 53 code=code, 54 ) 55 56 get_strategy_code_response_200.additional_properties = d 57 return get_strategy_code_response_200 58 59 @property 60 def additional_keys(self) -> list[str]: 61 return list(self.additional_properties.keys()) 62 63 def __getitem__(self, key: str) -> Any: 64 return self.additional_properties[key] 65 66 def __setitem__(self, key: str, value: Any) -> None: 67 self.additional_properties[key] = value 68 69 def __delitem__(self, key: str) -> None: 70 del self.additional_properties[key] 71 72 def __contains__(self, key: str) -> bool: 73 return key in self.additional_properties
Attributes:
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
POST /strategy for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
code (str): Raw strategy Java source code, exactly as registered.
25def __init__(self, strategy_id, code): 26 self.strategy_id = strategy_id 27 self.code = code 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class GetStrategyCodeResponse200.
44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 strategy_id = d.pop("strategyId") 48 49 code = d.pop("code") 50 51 get_strategy_code_response_200 = cls( 52 strategy_id=strategy_id, 53 code=code, 54 ) 55 56 get_strategy_code_response_200.additional_properties = d 57 return get_strategy_code_response_200
5class GetSweepResultObjective(str, Enum): 6 MAXDD = "maxdd" 7 PNL = "pnl" 8 SHARPE = "sharpe" 9 SORTINO = "sortino" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class GetSweepResultOrder(str, Enum): 6 NATURAL = "natural" 7 RANKED = "ranked" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class GetSweepResultRanking(str, Enum): 6 PLATEAU = "plateau" 7 RAW = "raw" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class GetSweepSensitivityObjective(str, Enum): 6 MAXDD = "maxdd" 7 PNL = "pnl" 8 SHARPE = "sharpe" 9 SORTINO = "sortino" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
15@_attrs_define 16class HalLink: 17 """A HAL link object (Hypertext Application Language) 18 19 Attributes: 20 href (str): The link target as an absolute-path URI reference (resolve against the API base). A URI Template 21 (RFC 6570) when `templated` is true. Example: /v1/exchange/binance/spot/instruments. 22 templated (bool | Unset): True when `href` is an RFC 6570 URI Template. 23 """ 24 25 href: str 26 templated: bool | Unset = UNSET 27 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 28 29 def to_dict(self) -> dict[str, Any]: 30 href = self.href 31 32 templated = self.templated 33 34 field_dict: dict[str, Any] = {} 35 field_dict.update(self.additional_properties) 36 field_dict.update( 37 { 38 "href": href, 39 } 40 ) 41 if templated is not UNSET: 42 field_dict["templated"] = templated 43 44 return field_dict 45 46 @classmethod 47 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 48 d = dict(src_dict) 49 href = d.pop("href") 50 51 templated = d.pop("templated", UNSET) 52 53 hal_link = cls( 54 href=href, 55 templated=templated, 56 ) 57 58 hal_link.additional_properties = d 59 return hal_link 60 61 @property 62 def additional_keys(self) -> list[str]: 63 return list(self.additional_properties.keys()) 64 65 def __getitem__(self, key: str) -> Any: 66 return self.additional_properties[key] 67 68 def __setitem__(self, key: str, value: Any) -> None: 69 self.additional_properties[key] = value 70 71 def __delitem__(self, key: str) -> None: 72 del self.additional_properties[key] 73 74 def __contains__(self, key: str) -> bool: 75 return key in self.additional_properties
A HAL link object (Hypertext Application Language)
Attributes:
href (str): The link target as an absolute-path URI reference (resolve against the API base). A URI Template
(RFC 6570) when templated is true. Example: /v1/exchange/binance/spot/instruments.
templated (bool | Unset): True when href is an RFC 6570 URI Template.
25def __init__(self, href, templated=attr_dict['templated'].default): 26 self.href = href 27 self.templated = templated 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class HalLink.
29 def to_dict(self) -> dict[str, Any]: 30 href = self.href 31 32 templated = self.templated 33 34 field_dict: dict[str, Any] = {} 35 field_dict.update(self.additional_properties) 36 field_dict.update( 37 { 38 "href": href, 39 } 40 ) 41 if templated is not UNSET: 42 field_dict["templated"] = templated 43 44 return field_dict
19@_attrs_define 20class InstrumentCoverage: 21 """Time coverage of available data for this instrument, per data type 22 23 Attributes: 24 tickers (CoverageWindow | Unset): The time range of available data for a single data type 25 klines (CoverageWindow | Unset): The time range of available data for a single data type 26 """ 27 28 tickers: CoverageWindow | Unset = UNSET 29 klines: CoverageWindow | Unset = UNSET 30 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 31 32 def to_dict(self) -> dict[str, Any]: 33 tickers: dict[str, Any] | Unset = UNSET 34 if not isinstance(self.tickers, Unset): 35 tickers = self.tickers.to_dict() 36 37 klines: dict[str, Any] | Unset = UNSET 38 if not isinstance(self.klines, Unset): 39 klines = self.klines.to_dict() 40 41 field_dict: dict[str, Any] = {} 42 field_dict.update(self.additional_properties) 43 field_dict.update({}) 44 if tickers is not UNSET: 45 field_dict["tickers"] = tickers 46 if klines is not UNSET: 47 field_dict["klines"] = klines 48 49 return field_dict 50 51 @classmethod 52 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 53 from ..models.coverage_window import CoverageWindow 54 55 d = dict(src_dict) 56 _tickers = d.pop("tickers", UNSET) 57 tickers: CoverageWindow | Unset 58 if isinstance(_tickers, Unset): 59 tickers = UNSET 60 else: 61 tickers = CoverageWindow.from_dict(_tickers) 62 63 _klines = d.pop("klines", UNSET) 64 klines: CoverageWindow | Unset 65 if isinstance(_klines, Unset): 66 klines = UNSET 67 else: 68 klines = CoverageWindow.from_dict(_klines) 69 70 instrument_coverage = cls( 71 tickers=tickers, 72 klines=klines, 73 ) 74 75 instrument_coverage.additional_properties = d 76 return instrument_coverage 77 78 @property 79 def additional_keys(self) -> list[str]: 80 return list(self.additional_properties.keys()) 81 82 def __getitem__(self, key: str) -> Any: 83 return self.additional_properties[key] 84 85 def __setitem__(self, key: str, value: Any) -> None: 86 self.additional_properties[key] = value 87 88 def __delitem__(self, key: str) -> None: 89 del self.additional_properties[key] 90 91 def __contains__(self, key: str) -> bool: 92 return key in self.additional_properties
Time coverage of available data for this instrument, per data type
Attributes: tickers (CoverageWindow | Unset): The time range of available data for a single data type klines (CoverageWindow | Unset): The time range of available data for a single data type
25def __init__(self, tickers=attr_dict['tickers'].default, klines=attr_dict['klines'].default): 26 self.tickers = tickers 27 self.klines = klines 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class InstrumentCoverage.
32 def to_dict(self) -> dict[str, Any]: 33 tickers: dict[str, Any] | Unset = UNSET 34 if not isinstance(self.tickers, Unset): 35 tickers = self.tickers.to_dict() 36 37 klines: dict[str, Any] | Unset = UNSET 38 if not isinstance(self.klines, Unset): 39 klines = self.klines.to_dict() 40 41 field_dict: dict[str, Any] = {} 42 field_dict.update(self.additional_properties) 43 field_dict.update({}) 44 if tickers is not UNSET: 45 field_dict["tickers"] = tickers 46 if klines is not UNSET: 47 field_dict["klines"] = klines 48 49 return field_dict
51 @classmethod 52 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 53 from ..models.coverage_window import CoverageWindow 54 55 d = dict(src_dict) 56 _tickers = d.pop("tickers", UNSET) 57 tickers: CoverageWindow | Unset 58 if isinstance(_tickers, Unset): 59 tickers = UNSET 60 else: 61 tickers = CoverageWindow.from_dict(_tickers) 62 63 _klines = d.pop("klines", UNSET) 64 klines: CoverageWindow | Unset 65 if isinstance(_klines, Unset): 66 klines = UNSET 67 else: 68 klines = CoverageWindow.from_dict(_klines) 69 70 instrument_coverage = cls( 71 tickers=tickers, 72 klines=klines, 73 ) 74 75 instrument_coverage.additional_properties = d 76 return instrument_coverage
19@_attrs_define 20class InstrumentDetail: 21 """Exchange instrument with per-data-type coverage and market info 22 23 Attributes: 24 id (str): Instrument identifier (e.g. currency pair) Example: BTC/USDT. 25 base (str): Base currency Example: BTC. 26 quote (str): Quote currency Example: USDT. 27 coverage (InstrumentCoverage | Unset): Time coverage of available data for this instrument, per data type 28 last_price (float | Unset): Last traded price Example: 84250.5. 29 volume24h (float | Unset): Trading volume in the last 24 hours (in quote currency) Example: 1234567.89. 30 """ 31 32 id: str 33 base: str 34 quote: str 35 coverage: InstrumentCoverage | Unset = UNSET 36 last_price: float | Unset = UNSET 37 volume24h: float | Unset = UNSET 38 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 39 40 def to_dict(self) -> dict[str, Any]: 41 id = self.id 42 43 base = self.base 44 45 quote = self.quote 46 47 coverage: dict[str, Any] | Unset = UNSET 48 if not isinstance(self.coverage, Unset): 49 coverage = self.coverage.to_dict() 50 51 last_price = self.last_price 52 53 volume24h = self.volume24h 54 55 field_dict: dict[str, Any] = {} 56 field_dict.update(self.additional_properties) 57 field_dict.update( 58 { 59 "id": id, 60 "base": base, 61 "quote": quote, 62 } 63 ) 64 if coverage is not UNSET: 65 field_dict["coverage"] = coverage 66 if last_price is not UNSET: 67 field_dict["lastPrice"] = last_price 68 if volume24h is not UNSET: 69 field_dict["volume24h"] = volume24h 70 71 return field_dict 72 73 @classmethod 74 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 75 from ..models.instrument_coverage import InstrumentCoverage 76 77 d = dict(src_dict) 78 id = d.pop("id") 79 80 base = d.pop("base") 81 82 quote = d.pop("quote") 83 84 _coverage = d.pop("coverage", UNSET) 85 coverage: InstrumentCoverage | Unset 86 if isinstance(_coverage, Unset): 87 coverage = UNSET 88 else: 89 coverage = InstrumentCoverage.from_dict(_coverage) 90 91 last_price = d.pop("lastPrice", UNSET) 92 93 volume24h = d.pop("volume24h", UNSET) 94 95 instrument_detail = cls( 96 id=id, 97 base=base, 98 quote=quote, 99 coverage=coverage, 100 last_price=last_price, 101 volume24h=volume24h, 102 ) 103 104 instrument_detail.additional_properties = d 105 return instrument_detail 106 107 @property 108 def additional_keys(self) -> list[str]: 109 return list(self.additional_properties.keys()) 110 111 def __getitem__(self, key: str) -> Any: 112 return self.additional_properties[key] 113 114 def __setitem__(self, key: str, value: Any) -> None: 115 self.additional_properties[key] = value 116 117 def __delitem__(self, key: str) -> None: 118 del self.additional_properties[key] 119 120 def __contains__(self, key: str) -> bool: 121 return key in self.additional_properties
Exchange instrument with per-data-type coverage and market info
Attributes: id (str): Instrument identifier (e.g. currency pair) Example: BTC/USDT. base (str): Base currency Example: BTC. quote (str): Quote currency Example: USDT. coverage (InstrumentCoverage | Unset): Time coverage of available data for this instrument, per data type last_price (float | Unset): Last traded price Example: 84250.5. volume24h (float | Unset): Trading volume in the last 24 hours (in quote currency) Example: 1234567.89.
29def __init__(self, id, base, quote, coverage=attr_dict['coverage'].default, last_price=attr_dict['last_price'].default, volume24h=attr_dict['volume24h'].default): 30 self.id = id 31 self.base = base 32 self.quote = quote 33 self.coverage = coverage 34 self.last_price = last_price 35 self.volume24h = volume24h 36 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class InstrumentDetail.
40 def to_dict(self) -> dict[str, Any]: 41 id = self.id 42 43 base = self.base 44 45 quote = self.quote 46 47 coverage: dict[str, Any] | Unset = UNSET 48 if not isinstance(self.coverage, Unset): 49 coverage = self.coverage.to_dict() 50 51 last_price = self.last_price 52 53 volume24h = self.volume24h 54 55 field_dict: dict[str, Any] = {} 56 field_dict.update(self.additional_properties) 57 field_dict.update( 58 { 59 "id": id, 60 "base": base, 61 "quote": quote, 62 } 63 ) 64 if coverage is not UNSET: 65 field_dict["coverage"] = coverage 66 if last_price is not UNSET: 67 field_dict["lastPrice"] = last_price 68 if volume24h is not UNSET: 69 field_dict["volume24h"] = volume24h 70 71 return field_dict
73 @classmethod 74 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 75 from ..models.instrument_coverage import InstrumentCoverage 76 77 d = dict(src_dict) 78 id = d.pop("id") 79 80 base = d.pop("base") 81 82 quote = d.pop("quote") 83 84 _coverage = d.pop("coverage", UNSET) 85 coverage: InstrumentCoverage | Unset 86 if isinstance(_coverage, Unset): 87 coverage = UNSET 88 else: 89 coverage = InstrumentCoverage.from_dict(_coverage) 90 91 last_price = d.pop("lastPrice", UNSET) 92 93 volume24h = d.pop("volume24h", UNSET) 94 95 instrument_detail = cls( 96 id=id, 97 base=base, 98 quote=quote, 99 coverage=coverage, 100 last_price=last_price, 101 volume24h=volume24h, 102 ) 103 104 instrument_detail.additional_properties = d 105 return instrument_detail
19@_attrs_define 20class InstrumentLinks: 21 """HAL `_links` — segment discovery for the instruments listing 22 23 Attributes: 24 self_ (HalLink): A HAL link object (Hypertext Application Language) 25 spot (HalLink | Unset): A HAL link object (Hypertext Application Language) 26 futures (HalLink | Unset): A HAL link object (Hypertext Application Language) 27 """ 28 29 self_: HalLink 30 spot: HalLink | Unset = UNSET 31 futures: HalLink | Unset = UNSET 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 self_ = self.self_.to_dict() 36 37 spot: dict[str, Any] | Unset = UNSET 38 if not isinstance(self.spot, Unset): 39 spot = self.spot.to_dict() 40 41 futures: dict[str, Any] | Unset = UNSET 42 if not isinstance(self.futures, Unset): 43 futures = self.futures.to_dict() 44 45 field_dict: dict[str, Any] = {} 46 field_dict.update(self.additional_properties) 47 field_dict.update( 48 { 49 "self": self_, 50 } 51 ) 52 if spot is not UNSET: 53 field_dict["spot"] = spot 54 if futures is not UNSET: 55 field_dict["futures"] = futures 56 57 return field_dict 58 59 @classmethod 60 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 61 from ..models.hal_link import HalLink 62 63 d = dict(src_dict) 64 self_ = HalLink.from_dict(d.pop("self")) 65 66 _spot = d.pop("spot", UNSET) 67 spot: HalLink | Unset 68 if isinstance(_spot, Unset): 69 spot = UNSET 70 else: 71 spot = HalLink.from_dict(_spot) 72 73 _futures = d.pop("futures", UNSET) 74 futures: HalLink | Unset 75 if isinstance(_futures, Unset): 76 futures = UNSET 77 else: 78 futures = HalLink.from_dict(_futures) 79 80 instrument_links = cls( 81 self_=self_, 82 spot=spot, 83 futures=futures, 84 ) 85 86 instrument_links.additional_properties = d 87 return instrument_links 88 89 @property 90 def additional_keys(self) -> list[str]: 91 return list(self.additional_properties.keys()) 92 93 def __getitem__(self, key: str) -> Any: 94 return self.additional_properties[key] 95 96 def __setitem__(self, key: str, value: Any) -> None: 97 self.additional_properties[key] = value 98 99 def __delitem__(self, key: str) -> None: 100 del self.additional_properties[key] 101 102 def __contains__(self, key: str) -> bool: 103 return key in self.additional_properties
HAL _links — segment discovery for the instruments listing
Attributes: self_ (HalLink): A HAL link object (Hypertext Application Language) spot (HalLink | Unset): A HAL link object (Hypertext Application Language) futures (HalLink | Unset): A HAL link object (Hypertext Application Language)
26def __init__(self, self_, spot=attr_dict['spot'].default, futures=attr_dict['futures'].default): 27 self.self_ = self_ 28 self.spot = spot 29 self.futures = futures 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class InstrumentLinks.
34 def to_dict(self) -> dict[str, Any]: 35 self_ = self.self_.to_dict() 36 37 spot: dict[str, Any] | Unset = UNSET 38 if not isinstance(self.spot, Unset): 39 spot = self.spot.to_dict() 40 41 futures: dict[str, Any] | Unset = UNSET 42 if not isinstance(self.futures, Unset): 43 futures = self.futures.to_dict() 44 45 field_dict: dict[str, Any] = {} 46 field_dict.update(self.additional_properties) 47 field_dict.update( 48 { 49 "self": self_, 50 } 51 ) 52 if spot is not UNSET: 53 field_dict["spot"] = spot 54 if futures is not UNSET: 55 field_dict["futures"] = futures 56 57 return field_dict
59 @classmethod 60 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 61 from ..models.hal_link import HalLink 62 63 d = dict(src_dict) 64 self_ = HalLink.from_dict(d.pop("self")) 65 66 _spot = d.pop("spot", UNSET) 67 spot: HalLink | Unset 68 if isinstance(_spot, Unset): 69 spot = UNSET 70 else: 71 spot = HalLink.from_dict(_spot) 72 73 _futures = d.pop("futures", UNSET) 74 futures: HalLink | Unset 75 if isinstance(_futures, Unset): 76 futures = UNSET 77 else: 78 futures = HalLink.from_dict(_futures) 79 80 instrument_links = cls( 81 self_=self_, 82 spot=spot, 83 futures=futures, 84 ) 85 86 instrument_links.additional_properties = d 87 return instrument_links
17@_attrs_define 18class InstrumentListMeta: 19 """Metadata describing the instruments listing 20 21 Attributes: 22 updated_at (datetime.datetime): When this listing was last refreshed Example: 2026-07-09T19:09:07Z. 23 exchange (str): The exchange the instruments belong to Example: binance. 24 segment (InstrumentListMetaSegment): The market segment served in `data` Example: spot. 25 """ 26 27 updated_at: datetime.datetime 28 exchange: str 29 segment: InstrumentListMetaSegment 30 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 31 32 def to_dict(self) -> dict[str, Any]: 33 updated_at = self.updated_at.isoformat() 34 35 exchange = self.exchange 36 37 segment = self.segment.value 38 39 field_dict: dict[str, Any] = {} 40 field_dict.update(self.additional_properties) 41 field_dict.update( 42 { 43 "updatedAt": updated_at, 44 "exchange": exchange, 45 "segment": segment, 46 } 47 ) 48 49 return field_dict 50 51 @classmethod 52 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 53 d = dict(src_dict) 54 updated_at = isoparse(d.pop("updatedAt")) 55 56 exchange = d.pop("exchange") 57 58 segment = InstrumentListMetaSegment(d.pop("segment")) 59 60 instrument_list_meta = cls( 61 updated_at=updated_at, 62 exchange=exchange, 63 segment=segment, 64 ) 65 66 instrument_list_meta.additional_properties = d 67 return instrument_list_meta 68 69 @property 70 def additional_keys(self) -> list[str]: 71 return list(self.additional_properties.keys()) 72 73 def __getitem__(self, key: str) -> Any: 74 return self.additional_properties[key] 75 76 def __setitem__(self, key: str, value: Any) -> None: 77 self.additional_properties[key] = value 78 79 def __delitem__(self, key: str) -> None: 80 del self.additional_properties[key] 81 82 def __contains__(self, key: str) -> bool: 83 return key in self.additional_properties
Metadata describing the instruments listing
Attributes:
updated_at (datetime.datetime): When this listing was last refreshed Example: 2026-07-09T19:09:07Z.
exchange (str): The exchange the instruments belong to Example: binance.
segment (InstrumentListMetaSegment): The market segment served in data Example: spot.
26def __init__(self, updated_at, exchange, segment): 27 self.updated_at = updated_at 28 self.exchange = exchange 29 self.segment = segment 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class InstrumentListMeta.
32 def to_dict(self) -> dict[str, Any]: 33 updated_at = self.updated_at.isoformat() 34 35 exchange = self.exchange 36 37 segment = self.segment.value 38 39 field_dict: dict[str, Any] = {} 40 field_dict.update(self.additional_properties) 41 field_dict.update( 42 { 43 "updatedAt": updated_at, 44 "exchange": exchange, 45 "segment": segment, 46 } 47 ) 48 49 return field_dict
51 @classmethod 52 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 53 d = dict(src_dict) 54 updated_at = isoparse(d.pop("updatedAt")) 55 56 exchange = d.pop("exchange") 57 58 segment = InstrumentListMetaSegment(d.pop("segment")) 59 60 instrument_list_meta = cls( 61 updated_at=updated_at, 62 exchange=exchange, 63 segment=segment, 64 ) 65 66 instrument_list_meta.additional_properties = d 67 return instrument_list_meta
5class InstrumentListMetaSegment(str, Enum): 6 FUTURES = "futures" 7 SPOT = "spot" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
19@_attrs_define 20class InstrumentListResponse: 21 """HAL-style response envelope for the instruments listing 22 23 Attributes: 24 data (list[InstrumentDetail]): The list of instruments for the segment 25 meta (InstrumentListMeta): Metadata describing the instruments listing 26 field_links (InstrumentLinks): HAL `_links` — segment discovery for the instruments listing 27 """ 28 29 data: list[InstrumentDetail] 30 meta: InstrumentListMeta 31 field_links: InstrumentLinks 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 data = [] 36 for data_item_data in self.data: 37 data_item = data_item_data.to_dict() 38 data.append(data_item) 39 40 meta = self.meta.to_dict() 41 42 field_links = self.field_links.to_dict() 43 44 field_dict: dict[str, Any] = {} 45 field_dict.update(self.additional_properties) 46 field_dict.update( 47 { 48 "data": data, 49 "meta": meta, 50 "_links": field_links, 51 } 52 ) 53 54 return field_dict 55 56 @classmethod 57 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 58 from ..models.instrument_detail import InstrumentDetail 59 from ..models.instrument_links import InstrumentLinks 60 from ..models.instrument_list_meta import InstrumentListMeta 61 62 d = dict(src_dict) 63 data = [] 64 _data = d.pop("data") 65 for data_item_data in _data: 66 data_item = InstrumentDetail.from_dict(data_item_data) 67 68 data.append(data_item) 69 70 meta = InstrumentListMeta.from_dict(d.pop("meta")) 71 72 field_links = InstrumentLinks.from_dict(d.pop("_links")) 73 74 instrument_list_response = cls( 75 data=data, 76 meta=meta, 77 field_links=field_links, 78 ) 79 80 instrument_list_response.additional_properties = d 81 return instrument_list_response 82 83 @property 84 def additional_keys(self) -> list[str]: 85 return list(self.additional_properties.keys()) 86 87 def __getitem__(self, key: str) -> Any: 88 return self.additional_properties[key] 89 90 def __setitem__(self, key: str, value: Any) -> None: 91 self.additional_properties[key] = value 92 93 def __delitem__(self, key: str) -> None: 94 del self.additional_properties[key] 95 96 def __contains__(self, key: str) -> bool: 97 return key in self.additional_properties
HAL-style response envelope for the instruments listing
Attributes:
data (list[InstrumentDetail]): The list of instruments for the segment
meta (InstrumentListMeta): Metadata describing the instruments listing
field_links (InstrumentLinks): HAL _links — segment discovery for the instruments listing
26def __init__(self, data, meta, field_links): 27 self.data = data 28 self.meta = meta 29 self.field_links = field_links 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class InstrumentListResponse.
34 def to_dict(self) -> dict[str, Any]: 35 data = [] 36 for data_item_data in self.data: 37 data_item = data_item_data.to_dict() 38 data.append(data_item) 39 40 meta = self.meta.to_dict() 41 42 field_links = self.field_links.to_dict() 43 44 field_dict: dict[str, Any] = {} 45 field_dict.update(self.additional_properties) 46 field_dict.update( 47 { 48 "data": data, 49 "meta": meta, 50 "_links": field_links, 51 } 52 ) 53 54 return field_dict
56 @classmethod 57 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 58 from ..models.instrument_detail import InstrumentDetail 59 from ..models.instrument_links import InstrumentLinks 60 from ..models.instrument_list_meta import InstrumentListMeta 61 62 d = dict(src_dict) 63 data = [] 64 _data = d.pop("data") 65 for data_item_data in _data: 66 data_item = InstrumentDetail.from_dict(data_item_data) 67 68 data.append(data_item) 69 70 meta = InstrumentListMeta.from_dict(d.pop("meta")) 71 72 field_links = InstrumentLinks.from_dict(d.pop("_links")) 73 74 instrument_list_response = cls( 75 data=data, 76 meta=meta, 77 field_links=field_links, 78 ) 79 80 instrument_list_response.additional_properties = d 81 return instrument_list_response
18@_attrs_define 19class JobState: 20 """Information about a single job 21 22 Attributes: 23 context_id (str): Opaque context identifier for the job Example: ctx_2o8heaioicr0edvx5ybcap. 24 status (JobStateStatus): Current status of the job. Treat `Completed | Aborted | Failed` as 25 terminal; `New | Started` mean keep polling. A single-instrument prepare 26 is always terminal (`Completed`) — decide from 27 `PrepareJobState.coverageRatio`, not by polling. 28 Example: Completed. 29 size (int): Total size of the data being prepared Example: 100. 30 completed (int): The amount of data processed so far Example: 50. 31 status_detail (None | str | Unset): Detailed status information, if available Example: Job completed with error 32 code 5001. 33 start_time (datetime.datetime | None | Unset): Timestamp for when the preparation started Example: 34 2025-01-04T14:00:00Z. 35 end_time (datetime.datetime | None | Unset): Timestamp for when the preparation finished Example: 36 2025-01-04T14:00:20Z. 37 """ 38 39 context_id: str 40 status: JobStateStatus 41 size: int 42 completed: int 43 status_detail: None | str | Unset = UNSET 44 start_time: datetime.datetime | None | Unset = UNSET 45 end_time: datetime.datetime | None | Unset = UNSET 46 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 47 48 def to_dict(self) -> dict[str, Any]: 49 context_id = self.context_id 50 51 status = self.status.value 52 53 size = self.size 54 55 completed = self.completed 56 57 status_detail: None | str | Unset 58 if isinstance(self.status_detail, Unset): 59 status_detail = UNSET 60 else: 61 status_detail = self.status_detail 62 63 start_time: None | str | Unset 64 if isinstance(self.start_time, Unset): 65 start_time = UNSET 66 elif isinstance(self.start_time, datetime.datetime): 67 start_time = self.start_time.isoformat() 68 else: 69 start_time = self.start_time 70 71 end_time: None | str | Unset 72 if isinstance(self.end_time, Unset): 73 end_time = UNSET 74 elif isinstance(self.end_time, datetime.datetime): 75 end_time = self.end_time.isoformat() 76 else: 77 end_time = self.end_time 78 79 field_dict: dict[str, Any] = {} 80 field_dict.update(self.additional_properties) 81 field_dict.update( 82 { 83 "contextId": context_id, 84 "status": status, 85 "size": size, 86 "completed": completed, 87 } 88 ) 89 if status_detail is not UNSET: 90 field_dict["statusDetail"] = status_detail 91 if start_time is not UNSET: 92 field_dict["startTime"] = start_time 93 if end_time is not UNSET: 94 field_dict["endTime"] = end_time 95 96 return field_dict 97 98 @classmethod 99 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 100 d = dict(src_dict) 101 context_id = d.pop("contextId") 102 103 status = JobStateStatus(d.pop("status")) 104 105 size = d.pop("size") 106 107 completed = d.pop("completed") 108 109 def _parse_status_detail(data: object) -> None | str | Unset: 110 if data is None: 111 return data 112 if isinstance(data, Unset): 113 return data 114 return cast(None | str | Unset, data) 115 116 status_detail = _parse_status_detail(d.pop("statusDetail", UNSET)) 117 118 def _parse_start_time(data: object) -> datetime.datetime | None | Unset: 119 if data is None: 120 return data 121 if isinstance(data, Unset): 122 return data 123 try: 124 if not isinstance(data, str): 125 raise TypeError() 126 start_time_type_0 = isoparse(data) 127 128 return start_time_type_0 129 except (TypeError, ValueError, AttributeError, KeyError): 130 pass 131 return cast(datetime.datetime | None | Unset, data) 132 133 start_time = _parse_start_time(d.pop("startTime", UNSET)) 134 135 def _parse_end_time(data: object) -> datetime.datetime | None | Unset: 136 if data is None: 137 return data 138 if isinstance(data, Unset): 139 return data 140 try: 141 if not isinstance(data, str): 142 raise TypeError() 143 end_time_type_0 = isoparse(data) 144 145 return end_time_type_0 146 except (TypeError, ValueError, AttributeError, KeyError): 147 pass 148 return cast(datetime.datetime | None | Unset, data) 149 150 end_time = _parse_end_time(d.pop("endTime", UNSET)) 151 152 job_state = cls( 153 context_id=context_id, 154 status=status, 155 size=size, 156 completed=completed, 157 status_detail=status_detail, 158 start_time=start_time, 159 end_time=end_time, 160 ) 161 162 job_state.additional_properties = d 163 return job_state 164 165 @property 166 def additional_keys(self) -> list[str]: 167 return list(self.additional_properties.keys()) 168 169 def __getitem__(self, key: str) -> Any: 170 return self.additional_properties[key] 171 172 def __setitem__(self, key: str, value: Any) -> None: 173 self.additional_properties[key] = value 174 175 def __delitem__(self, key: str) -> None: 176 del self.additional_properties[key] 177 178 def __contains__(self, key: str) -> bool: 179 return key in self.additional_properties
Information about a single job
Attributes:
context_id (str): Opaque context identifier for the job Example: ctx_2o8heaioicr0edvx5ybcap.
status (JobStateStatus): Current status of the job. Treat Completed | Aborted | Failed as
terminal; New | Started mean keep polling. A single-instrument prepare
is always terminal (Completed) — decide from
PrepareJobState.coverageRatio, not by polling.
Example: Completed.
size (int): Total size of the data being prepared Example: 100.
completed (int): The amount of data processed so far Example: 50.
status_detail (None | str | Unset): Detailed status information, if available Example: Job completed with error
code 5001.
start_time (datetime.datetime | None | Unset): Timestamp for when the preparation started Example:
2025-01-04T14:00:00Z.
end_time (datetime.datetime | None | Unset): Timestamp for when the preparation finished Example:
2025-01-04T14:00:20Z.
30def __init__(self, context_id, status, size, completed, status_detail=attr_dict['status_detail'].default, start_time=attr_dict['start_time'].default, end_time=attr_dict['end_time'].default): 31 self.context_id = context_id 32 self.status = status 33 self.size = size 34 self.completed = completed 35 self.status_detail = status_detail 36 self.start_time = start_time 37 self.end_time = end_time 38 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class JobState.
48 def to_dict(self) -> dict[str, Any]: 49 context_id = self.context_id 50 51 status = self.status.value 52 53 size = self.size 54 55 completed = self.completed 56 57 status_detail: None | str | Unset 58 if isinstance(self.status_detail, Unset): 59 status_detail = UNSET 60 else: 61 status_detail = self.status_detail 62 63 start_time: None | str | Unset 64 if isinstance(self.start_time, Unset): 65 start_time = UNSET 66 elif isinstance(self.start_time, datetime.datetime): 67 start_time = self.start_time.isoformat() 68 else: 69 start_time = self.start_time 70 71 end_time: None | str | Unset 72 if isinstance(self.end_time, Unset): 73 end_time = UNSET 74 elif isinstance(self.end_time, datetime.datetime): 75 end_time = self.end_time.isoformat() 76 else: 77 end_time = self.end_time 78 79 field_dict: dict[str, Any] = {} 80 field_dict.update(self.additional_properties) 81 field_dict.update( 82 { 83 "contextId": context_id, 84 "status": status, 85 "size": size, 86 "completed": completed, 87 } 88 ) 89 if status_detail is not UNSET: 90 field_dict["statusDetail"] = status_detail 91 if start_time is not UNSET: 92 field_dict["startTime"] = start_time 93 if end_time is not UNSET: 94 field_dict["endTime"] = end_time 95 96 return field_dict
98 @classmethod 99 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 100 d = dict(src_dict) 101 context_id = d.pop("contextId") 102 103 status = JobStateStatus(d.pop("status")) 104 105 size = d.pop("size") 106 107 completed = d.pop("completed") 108 109 def _parse_status_detail(data: object) -> None | str | Unset: 110 if data is None: 111 return data 112 if isinstance(data, Unset): 113 return data 114 return cast(None | str | Unset, data) 115 116 status_detail = _parse_status_detail(d.pop("statusDetail", UNSET)) 117 118 def _parse_start_time(data: object) -> datetime.datetime | None | Unset: 119 if data is None: 120 return data 121 if isinstance(data, Unset): 122 return data 123 try: 124 if not isinstance(data, str): 125 raise TypeError() 126 start_time_type_0 = isoparse(data) 127 128 return start_time_type_0 129 except (TypeError, ValueError, AttributeError, KeyError): 130 pass 131 return cast(datetime.datetime | None | Unset, data) 132 133 start_time = _parse_start_time(d.pop("startTime", UNSET)) 134 135 def _parse_end_time(data: object) -> datetime.datetime | None | Unset: 136 if data is None: 137 return data 138 if isinstance(data, Unset): 139 return data 140 try: 141 if not isinstance(data, str): 142 raise TypeError() 143 end_time_type_0 = isoparse(data) 144 145 return end_time_type_0 146 except (TypeError, ValueError, AttributeError, KeyError): 147 pass 148 return cast(datetime.datetime | None | Unset, data) 149 150 end_time = _parse_end_time(d.pop("endTime", UNSET)) 151 152 job_state = cls( 153 context_id=context_id, 154 status=status, 155 size=size, 156 completed=completed, 157 status_detail=status_detail, 158 start_time=start_time, 159 end_time=end_time, 160 ) 161 162 job_state.additional_properties = d 163 return job_state
5class JobStateStatus(str, Enum): 6 ABORTED = "Aborted" 7 COMPLETED = "Completed" 8 FAILED = "Failed" 9 NEW = "New" 10 STARTED = "Started" 11 12 def __str__(self) -> str: 13 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class ListDatasetsResponse200: 19 """ 20 Attributes: 21 datasets (list[Dataset]): 22 """ 23 24 datasets: list[Dataset] 25 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 26 27 def to_dict(self) -> dict[str, Any]: 28 datasets = [] 29 for datasets_item_data in self.datasets: 30 datasets_item = datasets_item_data.to_dict() 31 datasets.append(datasets_item) 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "datasets": datasets, 38 } 39 ) 40 41 return field_dict 42 43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 from ..models.dataset import Dataset 46 47 d = dict(src_dict) 48 datasets = [] 49 _datasets = d.pop("datasets") 50 for datasets_item_data in _datasets: 51 datasets_item = Dataset.from_dict(datasets_item_data) 52 53 datasets.append(datasets_item) 54 55 list_datasets_response_200 = cls( 56 datasets=datasets, 57 ) 58 59 list_datasets_response_200.additional_properties = d 60 return list_datasets_response_200 61 62 @property 63 def additional_keys(self) -> list[str]: 64 return list(self.additional_properties.keys()) 65 66 def __getitem__(self, key: str) -> Any: 67 return self.additional_properties[key] 68 69 def __setitem__(self, key: str, value: Any) -> None: 70 self.additional_properties[key] = value 71 72 def __delitem__(self, key: str) -> None: 73 del self.additional_properties[key] 74 75 def __contains__(self, key: str) -> bool: 76 return key in self.additional_properties
Attributes: datasets (list[Dataset]):
24def __init__(self, datasets): 25 self.datasets = datasets 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ListDatasetsResponse200.
27 def to_dict(self) -> dict[str, Any]: 28 datasets = [] 29 for datasets_item_data in self.datasets: 30 datasets_item = datasets_item_data.to_dict() 31 datasets.append(datasets_item) 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "datasets": datasets, 38 } 39 ) 40 41 return field_dict
43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 from ..models.dataset import Dataset 46 47 d = dict(src_dict) 48 datasets = [] 49 _datasets = d.pop("datasets") 50 for datasets_item_data in _datasets: 51 datasets_item = Dataset.from_dict(datasets_item_data) 52 53 datasets.append(datasets_item) 54 55 list_datasets_response_200 = cls( 56 datasets=datasets, 57 ) 58 59 list_datasets_response_200.additional_properties = d 60 return list_datasets_response_200
5class ListSegmentInstrumentsSegment(str, Enum): 6 FUTURES = "futures" 7 SPOT = "spot" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class ListStrategiesResponse200: 19 """ 20 Attributes: 21 strategies (list[StrategySummary]): 22 """ 23 24 strategies: list[StrategySummary] 25 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 26 27 def to_dict(self) -> dict[str, Any]: 28 strategies = [] 29 for strategies_item_data in self.strategies: 30 strategies_item = strategies_item_data.to_dict() 31 strategies.append(strategies_item) 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "strategies": strategies, 38 } 39 ) 40 41 return field_dict 42 43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 from ..models.strategy_summary import StrategySummary 46 47 d = dict(src_dict) 48 strategies = [] 49 _strategies = d.pop("strategies") 50 for strategies_item_data in _strategies: 51 strategies_item = StrategySummary.from_dict(strategies_item_data) 52 53 strategies.append(strategies_item) 54 55 list_strategies_response_200 = cls( 56 strategies=strategies, 57 ) 58 59 list_strategies_response_200.additional_properties = d 60 return list_strategies_response_200 61 62 @property 63 def additional_keys(self) -> list[str]: 64 return list(self.additional_properties.keys()) 65 66 def __getitem__(self, key: str) -> Any: 67 return self.additional_properties[key] 68 69 def __setitem__(self, key: str, value: Any) -> None: 70 self.additional_properties[key] = value 71 72 def __delitem__(self, key: str) -> None: 73 del self.additional_properties[key] 74 75 def __contains__(self, key: str) -> bool: 76 return key in self.additional_properties
Attributes: strategies (list[StrategySummary]):
24def __init__(self, strategies): 25 self.strategies = strategies 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ListStrategiesResponse200.
27 def to_dict(self) -> dict[str, Any]: 28 strategies = [] 29 for strategies_item_data in self.strategies: 30 strategies_item = strategies_item_data.to_dict() 31 strategies.append(strategies_item) 32 33 field_dict: dict[str, Any] = {} 34 field_dict.update(self.additional_properties) 35 field_dict.update( 36 { 37 "strategies": strategies, 38 } 39 ) 40 41 return field_dict
43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 from ..models.strategy_summary import StrategySummary 46 47 d = dict(src_dict) 48 strategies = [] 49 _strategies = d.pop("strategies") 50 for strategies_item_data in _strategies: 51 strategies_item = StrategySummary.from_dict(strategies_item_data) 52 53 strategies.append(strategies_item) 54 55 list_strategies_response_200 = cls( 56 strategies=strategies, 57 ) 58 59 list_strategies_response_200.additional_properties = d 60 return list_strategies_response_200
16@_attrs_define 17class Notice: 18 """A diagnostic the engine raised while the strategy ran. Advisory: it describes something worth 19 knowing about how the strategy is wired, not necessarily an error. 20 21 Attributes: 22 level (str): Severity as the engine classified it. Example: WARN. 23 code (str): Stable identifier for the kind of finding; safe to match on. Example: indicator.bar-data-on-ticker- 24 path. 25 message (str): Human-readable explanation. Example: Indicator requires bar data but is on the ticker path. 26 provenance (NoticeProvenance | Unset): Where it came from, which matters because the two silences differ: an 27 empty list from a 28 real run (`execute`) is a clean bill of health, while an empty list from 29 `compile-dry-run` is only a lower bound over a bounded synthetic series. 30 Example: compile-dry-run. 31 """ 32 33 level: str 34 code: str 35 message: str 36 provenance: NoticeProvenance | Unset = UNSET 37 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 38 39 def to_dict(self) -> dict[str, Any]: 40 level = self.level 41 42 code = self.code 43 44 message = self.message 45 46 provenance: str | Unset = UNSET 47 if not isinstance(self.provenance, Unset): 48 provenance = self.provenance.value 49 50 field_dict: dict[str, Any] = {} 51 field_dict.update(self.additional_properties) 52 field_dict.update( 53 { 54 "level": level, 55 "code": code, 56 "message": message, 57 } 58 ) 59 if provenance is not UNSET: 60 field_dict["provenance"] = provenance 61 62 return field_dict 63 64 @classmethod 65 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 66 d = dict(src_dict) 67 level = d.pop("level") 68 69 code = d.pop("code") 70 71 message = d.pop("message") 72 73 _provenance = d.pop("provenance", UNSET) 74 provenance: NoticeProvenance | Unset 75 if isinstance(_provenance, Unset): 76 provenance = UNSET 77 else: 78 provenance = NoticeProvenance(_provenance) 79 80 notice = cls( 81 level=level, 82 code=code, 83 message=message, 84 provenance=provenance, 85 ) 86 87 notice.additional_properties = d 88 return notice 89 90 @property 91 def additional_keys(self) -> list[str]: 92 return list(self.additional_properties.keys()) 93 94 def __getitem__(self, key: str) -> Any: 95 return self.additional_properties[key] 96 97 def __setitem__(self, key: str, value: Any) -> None: 98 self.additional_properties[key] = value 99 100 def __delitem__(self, key: str) -> None: 101 del self.additional_properties[key] 102 103 def __contains__(self, key: str) -> bool: 104 return key in self.additional_properties
A diagnostic the engine raised while the strategy ran. Advisory: it describes something worth knowing about how the strategy is wired, not necessarily an error.
Attributes:
level (str): Severity as the engine classified it. Example: WARN.
code (str): Stable identifier for the kind of finding; safe to match on. Example: indicator.bar-data-on-ticker-
path.
message (str): Human-readable explanation. Example: Indicator requires bar data but is on the ticker path.
provenance (NoticeProvenance | Unset): Where it came from, which matters because the two silences differ: an
empty list from a
real run (`execute`) is a clean bill of health, while an empty list from
`compile-dry-run` is only a lower bound over a bounded synthetic series.
Example: compile-dry-run.
27def __init__(self, level, code, message, provenance=attr_dict['provenance'].default): 28 self.level = level 29 self.code = code 30 self.message = message 31 self.provenance = provenance 32 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class Notice.
39 def to_dict(self) -> dict[str, Any]: 40 level = self.level 41 42 code = self.code 43 44 message = self.message 45 46 provenance: str | Unset = UNSET 47 if not isinstance(self.provenance, Unset): 48 provenance = self.provenance.value 49 50 field_dict: dict[str, Any] = {} 51 field_dict.update(self.additional_properties) 52 field_dict.update( 53 { 54 "level": level, 55 "code": code, 56 "message": message, 57 } 58 ) 59 if provenance is not UNSET: 60 field_dict["provenance"] = provenance 61 62 return field_dict
64 @classmethod 65 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 66 d = dict(src_dict) 67 level = d.pop("level") 68 69 code = d.pop("code") 70 71 message = d.pop("message") 72 73 _provenance = d.pop("provenance", UNSET) 74 provenance: NoticeProvenance | Unset 75 if isinstance(_provenance, Unset): 76 provenance = UNSET 77 else: 78 provenance = NoticeProvenance(_provenance) 79 80 notice = cls( 81 level=level, 82 code=code, 83 message=message, 84 provenance=provenance, 85 ) 86 87 notice.additional_properties = d 88 return notice
5class NoticeProvenance(str, Enum): 6 COMPILE_DRY_RUN = "compile-dry-run" 7 EXECUTE = "execute" 8 9 def __str__(self) -> str: 10 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
22@_attrs_define 23class PrepareJobState: 24 """State of a single-instrument prepare job — the `JobState` shape plus a coverage summary. 25 A single-instrument prepare is always terminal (`status: Completed`): the client decides 26 what to do from `coverageRatio` (e.g. execute if it is at or above a chosen threshold) 27 rather than polling for missing hours that may never arrive — a missing hour for one 28 instrument usually means low activity, not missing data. 29 30 **Two coverage shapes, by exchange vs. dataset.** Against a managed exchange, coverage is 31 walked hour by hour: `totalHours`/`hoursWithData`/`hoursWithoutData`. Against a 32 dataset-backed prepare (`exchangeId: user`), coverage is reported on the dataset's own 33 cadence grid instead — hour-walking a daily dataset would report `1/24` and read as 34 broken — via `cadence`/`gaps`/`largestGapSteps`; `totalHours`/`hoursWithData`/ 35 `hoursWithoutData` are absent in that case. `dataFrom`/`dataTo`/`coverageRatio` are present 36 either way, computed accordingly. 37 38 Attributes: 39 context_id (str): Opaque context identifier for the job Example: ctx_2o8heaioicr0edvx5ybcap. 40 status (JobStateStatus): Current status of the job. Treat `Completed | Aborted | Failed` as 41 terminal; `New | Started` mean keep polling. A single-instrument prepare 42 is always terminal (`Completed`) — decide from 43 `PrepareJobState.coverageRatio`, not by polling. 44 Example: Completed. 45 size (int): Total size of the data being prepared Example: 100. 46 completed (int): The amount of data processed so far Example: 50. 47 status_detail (None | str | Unset): Detailed status information, if available Example: Job completed with error 48 code 5001. 49 start_time (datetime.datetime | None | Unset): Timestamp for when the preparation started Example: 50 2025-01-04T14:00:00Z. 51 end_time (datetime.datetime | None | Unset): Timestamp for when the preparation finished Example: 52 2025-01-04T14:00:20Z. 53 data_from (datetime.datetime | None | Unset): Start of the available data range for the prepared instrument. 54 Example: 2026-04-14T13:00:00Z. 55 data_to (datetime.datetime | None | Unset): End of the available data range for the prepared instrument. 56 Example: 2026-04-14T15:30:05Z. 57 coverage_ratio (float | Unset): Against a managed exchange: `hoursWithData / totalHours` in `[0,1]` (`1.0` when 58 `totalHours` is 0), the fraction of hours in the requested range that have served 59 data. Against a dataset (`exchangeId: user`): `rows / expectedStepsAtCadence` 60 over the dataset version's own range — echoing what ingest computed once, not 61 recomputed against a narrower prepare request. 62 Example: 0.994. 63 total_hours (int | Unset): Number of whole hours in the requested prepare range. Managed exchanges only — 64 absent for a dataset-backed prepare. 65 Example: 168. 66 hours_with_data (int | Unset): Number of hours in the range that have data. Managed exchanges only — absent for 67 a dataset-backed prepare. 68 Example: 167. 69 cadence (str | Unset): The dataset version's own discovered cadence (e.g. `1m`, `1h`). Only present for a 70 dataset-backed prepare (`exchangeId: user`). 71 Example: 1m. 72 gaps (int | Unset): Number of gaps in the dataset version at its own cadence, as discovered at ingest 73 time. Only present for a dataset-backed prepare. 74 largest_gap_steps (int | Unset): The largest gap in the dataset version, in units of its own cadence step. Only 75 present for a dataset-backed prepare. 76 hours_without_data (list[PrepareJobStateHoursWithoutDataItem] | Unset): One entry per hour in the range that has 77 no data, with a rationale. Managed 78 exchanges only — absent for a dataset-backed prepare. 79 """ 80 81 context_id: str 82 status: JobStateStatus 83 size: int 84 completed: int 85 status_detail: None | str | Unset = UNSET 86 start_time: datetime.datetime | None | Unset = UNSET 87 end_time: datetime.datetime | None | Unset = UNSET 88 data_from: datetime.datetime | None | Unset = UNSET 89 data_to: datetime.datetime | None | Unset = UNSET 90 coverage_ratio: float | Unset = UNSET 91 total_hours: int | Unset = UNSET 92 hours_with_data: int | Unset = UNSET 93 cadence: str | Unset = UNSET 94 gaps: int | Unset = UNSET 95 largest_gap_steps: int | Unset = UNSET 96 hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | Unset = UNSET 97 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 98 99 def to_dict(self) -> dict[str, Any]: 100 context_id = self.context_id 101 102 status = self.status.value 103 104 size = self.size 105 106 completed = self.completed 107 108 status_detail: None | str | Unset 109 if isinstance(self.status_detail, Unset): 110 status_detail = UNSET 111 else: 112 status_detail = self.status_detail 113 114 start_time: None | str | Unset 115 if isinstance(self.start_time, Unset): 116 start_time = UNSET 117 elif isinstance(self.start_time, datetime.datetime): 118 start_time = self.start_time.isoformat() 119 else: 120 start_time = self.start_time 121 122 end_time: None | str | Unset 123 if isinstance(self.end_time, Unset): 124 end_time = UNSET 125 elif isinstance(self.end_time, datetime.datetime): 126 end_time = self.end_time.isoformat() 127 else: 128 end_time = self.end_time 129 130 data_from: None | str | Unset 131 if isinstance(self.data_from, Unset): 132 data_from = UNSET 133 elif isinstance(self.data_from, datetime.datetime): 134 data_from = self.data_from.isoformat() 135 else: 136 data_from = self.data_from 137 138 data_to: None | str | Unset 139 if isinstance(self.data_to, Unset): 140 data_to = UNSET 141 elif isinstance(self.data_to, datetime.datetime): 142 data_to = self.data_to.isoformat() 143 else: 144 data_to = self.data_to 145 146 coverage_ratio = self.coverage_ratio 147 148 total_hours = self.total_hours 149 150 hours_with_data = self.hours_with_data 151 152 cadence = self.cadence 153 154 gaps = self.gaps 155 156 largest_gap_steps = self.largest_gap_steps 157 158 hours_without_data: list[dict[str, Any]] | Unset = UNSET 159 if not isinstance(self.hours_without_data, Unset): 160 hours_without_data = [] 161 for hours_without_data_item_data in self.hours_without_data: 162 hours_without_data_item = hours_without_data_item_data.to_dict() 163 hours_without_data.append(hours_without_data_item) 164 165 field_dict: dict[str, Any] = {} 166 field_dict.update(self.additional_properties) 167 field_dict.update( 168 { 169 "contextId": context_id, 170 "status": status, 171 "size": size, 172 "completed": completed, 173 } 174 ) 175 if status_detail is not UNSET: 176 field_dict["statusDetail"] = status_detail 177 if start_time is not UNSET: 178 field_dict["startTime"] = start_time 179 if end_time is not UNSET: 180 field_dict["endTime"] = end_time 181 if data_from is not UNSET: 182 field_dict["dataFrom"] = data_from 183 if data_to is not UNSET: 184 field_dict["dataTo"] = data_to 185 if coverage_ratio is not UNSET: 186 field_dict["coverageRatio"] = coverage_ratio 187 if total_hours is not UNSET: 188 field_dict["totalHours"] = total_hours 189 if hours_with_data is not UNSET: 190 field_dict["hoursWithData"] = hours_with_data 191 if cadence is not UNSET: 192 field_dict["cadence"] = cadence 193 if gaps is not UNSET: 194 field_dict["gaps"] = gaps 195 if largest_gap_steps is not UNSET: 196 field_dict["largestGapSteps"] = largest_gap_steps 197 if hours_without_data is not UNSET: 198 field_dict["hoursWithoutData"] = hours_without_data 199 200 return field_dict 201 202 @classmethod 203 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 204 from ..models.prepare_job_state_hours_without_data_item import PrepareJobStateHoursWithoutDataItem 205 206 d = dict(src_dict) 207 context_id = d.pop("contextId") 208 209 status = JobStateStatus(d.pop("status")) 210 211 size = d.pop("size") 212 213 completed = d.pop("completed") 214 215 def _parse_status_detail(data: object) -> None | str | Unset: 216 if data is None: 217 return data 218 if isinstance(data, Unset): 219 return data 220 return cast(None | str | Unset, data) 221 222 status_detail = _parse_status_detail(d.pop("statusDetail", UNSET)) 223 224 def _parse_start_time(data: object) -> datetime.datetime | None | Unset: 225 if data is None: 226 return data 227 if isinstance(data, Unset): 228 return data 229 try: 230 if not isinstance(data, str): 231 raise TypeError() 232 start_time_type_0 = isoparse(data) 233 234 return start_time_type_0 235 except (TypeError, ValueError, AttributeError, KeyError): 236 pass 237 return cast(datetime.datetime | None | Unset, data) 238 239 start_time = _parse_start_time(d.pop("startTime", UNSET)) 240 241 def _parse_end_time(data: object) -> datetime.datetime | None | Unset: 242 if data is None: 243 return data 244 if isinstance(data, Unset): 245 return data 246 try: 247 if not isinstance(data, str): 248 raise TypeError() 249 end_time_type_0 = isoparse(data) 250 251 return end_time_type_0 252 except (TypeError, ValueError, AttributeError, KeyError): 253 pass 254 return cast(datetime.datetime | None | Unset, data) 255 256 end_time = _parse_end_time(d.pop("endTime", UNSET)) 257 258 def _parse_data_from(data: object) -> datetime.datetime | None | Unset: 259 if data is None: 260 return data 261 if isinstance(data, Unset): 262 return data 263 try: 264 if not isinstance(data, str): 265 raise TypeError() 266 data_from_type_0 = isoparse(data) 267 268 return data_from_type_0 269 except (TypeError, ValueError, AttributeError, KeyError): 270 pass 271 return cast(datetime.datetime | None | Unset, data) 272 273 data_from = _parse_data_from(d.pop("dataFrom", UNSET)) 274 275 def _parse_data_to(data: object) -> datetime.datetime | None | Unset: 276 if data is None: 277 return data 278 if isinstance(data, Unset): 279 return data 280 try: 281 if not isinstance(data, str): 282 raise TypeError() 283 data_to_type_0 = isoparse(data) 284 285 return data_to_type_0 286 except (TypeError, ValueError, AttributeError, KeyError): 287 pass 288 return cast(datetime.datetime | None | Unset, data) 289 290 data_to = _parse_data_to(d.pop("dataTo", UNSET)) 291 292 coverage_ratio = d.pop("coverageRatio", UNSET) 293 294 total_hours = d.pop("totalHours", UNSET) 295 296 hours_with_data = d.pop("hoursWithData", UNSET) 297 298 cadence = d.pop("cadence", UNSET) 299 300 gaps = d.pop("gaps", UNSET) 301 302 largest_gap_steps = d.pop("largestGapSteps", UNSET) 303 304 _hours_without_data = d.pop("hoursWithoutData", UNSET) 305 hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | Unset = UNSET 306 if _hours_without_data is not UNSET: 307 hours_without_data = [] 308 for hours_without_data_item_data in _hours_without_data: 309 hours_without_data_item = PrepareJobStateHoursWithoutDataItem.from_dict(hours_without_data_item_data) 310 311 hours_without_data.append(hours_without_data_item) 312 313 prepare_job_state = cls( 314 context_id=context_id, 315 status=status, 316 size=size, 317 completed=completed, 318 status_detail=status_detail, 319 start_time=start_time, 320 end_time=end_time, 321 data_from=data_from, 322 data_to=data_to, 323 coverage_ratio=coverage_ratio, 324 total_hours=total_hours, 325 hours_with_data=hours_with_data, 326 cadence=cadence, 327 gaps=gaps, 328 largest_gap_steps=largest_gap_steps, 329 hours_without_data=hours_without_data, 330 ) 331 332 prepare_job_state.additional_properties = d 333 return prepare_job_state 334 335 @property 336 def additional_keys(self) -> list[str]: 337 return list(self.additional_properties.keys()) 338 339 def __getitem__(self, key: str) -> Any: 340 return self.additional_properties[key] 341 342 def __setitem__(self, key: str, value: Any) -> None: 343 self.additional_properties[key] = value 344 345 def __delitem__(self, key: str) -> None: 346 del self.additional_properties[key] 347 348 def __contains__(self, key: str) -> bool: 349 return key in self.additional_properties
State of a single-instrument prepare job — the JobState shape plus a coverage summary.
A single-instrument prepare is always terminal (status: Completed): the client decides
what to do from coverageRatio (e.g. execute if it is at or above a chosen threshold)
rather than polling for missing hours that may never arrive — a missing hour for one
instrument usually means low activity, not missing data.
Two coverage shapes, by exchange vs. dataset. Against a managed exchange, coverage is
walked hour by hour: totalHours/hoursWithData/hoursWithoutData. Against a
dataset-backed prepare (exchangeId: user), coverage is reported on the dataset's own
cadence grid instead — hour-walking a daily dataset would report 1/24 and read as
broken — via cadence/gaps/largestGapSteps; totalHours/hoursWithData/
hoursWithoutData are absent in that case. dataFrom/dataTo/coverageRatio are present
either way, computed accordingly.
Attributes:
context_id (str): Opaque context identifier for the job Example: ctx_2o8heaioicr0edvx5ybcap.
status (JobStateStatus): Current status of the job. Treat `Completed | Aborted | Failed` as
terminal; `New | Started` mean keep polling. A single-instrument prepare
is always terminal (`Completed`) — decide from
`PrepareJobState.coverageRatio`, not by polling.
Example: Completed.
size (int): Total size of the data being prepared Example: 100.
completed (int): The amount of data processed so far Example: 50.
status_detail (None | str | Unset): Detailed status information, if available Example: Job completed with error
code 5001.
start_time (datetime.datetime | None | Unset): Timestamp for when the preparation started Example:
2025-01-04T14:00:00Z.
end_time (datetime.datetime | None | Unset): Timestamp for when the preparation finished Example:
2025-01-04T14:00:20Z.
data_from (datetime.datetime | None | Unset): Start of the available data range for the prepared instrument.
Example: 2026-04-14T13:00:00Z.
data_to (datetime.datetime | None | Unset): End of the available data range for the prepared instrument.
Example: 2026-04-14T15:30:05Z.
coverage_ratio (float | Unset): Against a managed exchange: `hoursWithData / totalHours` in `[0,1]` (`1.0` when
`totalHours` is 0), the fraction of hours in the requested range that have served
data. Against a dataset (`exchangeId: user`): `rows / expectedStepsAtCadence`
over the dataset version's own range — echoing what ingest computed once, not
recomputed against a narrower prepare request.
Example: 0.994.
total_hours (int | Unset): Number of whole hours in the requested prepare range. Managed exchanges only —
absent for a dataset-backed prepare.
Example: 168.
hours_with_data (int | Unset): Number of hours in the range that have data. Managed exchanges only — absent for
a dataset-backed prepare.
Example: 167.
cadence (str | Unset): The dataset version's own discovered cadence (e.g. `1m`, `1h`). Only present for a
dataset-backed prepare (`exchangeId: user`).
Example: 1m.
gaps (int | Unset): Number of gaps in the dataset version at its own cadence, as discovered at ingest
time. Only present for a dataset-backed prepare.
largest_gap_steps (int | Unset): The largest gap in the dataset version, in units of its own cadence step. Only
present for a dataset-backed prepare.
hours_without_data (list[PrepareJobStateHoursWithoutDataItem] | Unset): One entry per hour in the range that has
no data, with a rationale. Managed
exchanges only — absent for a dataset-backed prepare.
39def __init__(self, context_id, status, size, completed, status_detail=attr_dict['status_detail'].default, start_time=attr_dict['start_time'].default, end_time=attr_dict['end_time'].default, data_from=attr_dict['data_from'].default, data_to=attr_dict['data_to'].default, coverage_ratio=attr_dict['coverage_ratio'].default, total_hours=attr_dict['total_hours'].default, hours_with_data=attr_dict['hours_with_data'].default, cadence=attr_dict['cadence'].default, gaps=attr_dict['gaps'].default, largest_gap_steps=attr_dict['largest_gap_steps'].default, hours_without_data=attr_dict['hours_without_data'].default): 40 self.context_id = context_id 41 self.status = status 42 self.size = size 43 self.completed = completed 44 self.status_detail = status_detail 45 self.start_time = start_time 46 self.end_time = end_time 47 self.data_from = data_from 48 self.data_to = data_to 49 self.coverage_ratio = coverage_ratio 50 self.total_hours = total_hours 51 self.hours_with_data = hours_with_data 52 self.cadence = cadence 53 self.gaps = gaps 54 self.largest_gap_steps = largest_gap_steps 55 self.hours_without_data = hours_without_data 56 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class PrepareJobState.
99 def to_dict(self) -> dict[str, Any]: 100 context_id = self.context_id 101 102 status = self.status.value 103 104 size = self.size 105 106 completed = self.completed 107 108 status_detail: None | str | Unset 109 if isinstance(self.status_detail, Unset): 110 status_detail = UNSET 111 else: 112 status_detail = self.status_detail 113 114 start_time: None | str | Unset 115 if isinstance(self.start_time, Unset): 116 start_time = UNSET 117 elif isinstance(self.start_time, datetime.datetime): 118 start_time = self.start_time.isoformat() 119 else: 120 start_time = self.start_time 121 122 end_time: None | str | Unset 123 if isinstance(self.end_time, Unset): 124 end_time = UNSET 125 elif isinstance(self.end_time, datetime.datetime): 126 end_time = self.end_time.isoformat() 127 else: 128 end_time = self.end_time 129 130 data_from: None | str | Unset 131 if isinstance(self.data_from, Unset): 132 data_from = UNSET 133 elif isinstance(self.data_from, datetime.datetime): 134 data_from = self.data_from.isoformat() 135 else: 136 data_from = self.data_from 137 138 data_to: None | str | Unset 139 if isinstance(self.data_to, Unset): 140 data_to = UNSET 141 elif isinstance(self.data_to, datetime.datetime): 142 data_to = self.data_to.isoformat() 143 else: 144 data_to = self.data_to 145 146 coverage_ratio = self.coverage_ratio 147 148 total_hours = self.total_hours 149 150 hours_with_data = self.hours_with_data 151 152 cadence = self.cadence 153 154 gaps = self.gaps 155 156 largest_gap_steps = self.largest_gap_steps 157 158 hours_without_data: list[dict[str, Any]] | Unset = UNSET 159 if not isinstance(self.hours_without_data, Unset): 160 hours_without_data = [] 161 for hours_without_data_item_data in self.hours_without_data: 162 hours_without_data_item = hours_without_data_item_data.to_dict() 163 hours_without_data.append(hours_without_data_item) 164 165 field_dict: dict[str, Any] = {} 166 field_dict.update(self.additional_properties) 167 field_dict.update( 168 { 169 "contextId": context_id, 170 "status": status, 171 "size": size, 172 "completed": completed, 173 } 174 ) 175 if status_detail is not UNSET: 176 field_dict["statusDetail"] = status_detail 177 if start_time is not UNSET: 178 field_dict["startTime"] = start_time 179 if end_time is not UNSET: 180 field_dict["endTime"] = end_time 181 if data_from is not UNSET: 182 field_dict["dataFrom"] = data_from 183 if data_to is not UNSET: 184 field_dict["dataTo"] = data_to 185 if coverage_ratio is not UNSET: 186 field_dict["coverageRatio"] = coverage_ratio 187 if total_hours is not UNSET: 188 field_dict["totalHours"] = total_hours 189 if hours_with_data is not UNSET: 190 field_dict["hoursWithData"] = hours_with_data 191 if cadence is not UNSET: 192 field_dict["cadence"] = cadence 193 if gaps is not UNSET: 194 field_dict["gaps"] = gaps 195 if largest_gap_steps is not UNSET: 196 field_dict["largestGapSteps"] = largest_gap_steps 197 if hours_without_data is not UNSET: 198 field_dict["hoursWithoutData"] = hours_without_data 199 200 return field_dict
202 @classmethod 203 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 204 from ..models.prepare_job_state_hours_without_data_item import PrepareJobStateHoursWithoutDataItem 205 206 d = dict(src_dict) 207 context_id = d.pop("contextId") 208 209 status = JobStateStatus(d.pop("status")) 210 211 size = d.pop("size") 212 213 completed = d.pop("completed") 214 215 def _parse_status_detail(data: object) -> None | str | Unset: 216 if data is None: 217 return data 218 if isinstance(data, Unset): 219 return data 220 return cast(None | str | Unset, data) 221 222 status_detail = _parse_status_detail(d.pop("statusDetail", UNSET)) 223 224 def _parse_start_time(data: object) -> datetime.datetime | None | Unset: 225 if data is None: 226 return data 227 if isinstance(data, Unset): 228 return data 229 try: 230 if not isinstance(data, str): 231 raise TypeError() 232 start_time_type_0 = isoparse(data) 233 234 return start_time_type_0 235 except (TypeError, ValueError, AttributeError, KeyError): 236 pass 237 return cast(datetime.datetime | None | Unset, data) 238 239 start_time = _parse_start_time(d.pop("startTime", UNSET)) 240 241 def _parse_end_time(data: object) -> datetime.datetime | None | Unset: 242 if data is None: 243 return data 244 if isinstance(data, Unset): 245 return data 246 try: 247 if not isinstance(data, str): 248 raise TypeError() 249 end_time_type_0 = isoparse(data) 250 251 return end_time_type_0 252 except (TypeError, ValueError, AttributeError, KeyError): 253 pass 254 return cast(datetime.datetime | None | Unset, data) 255 256 end_time = _parse_end_time(d.pop("endTime", UNSET)) 257 258 def _parse_data_from(data: object) -> datetime.datetime | None | Unset: 259 if data is None: 260 return data 261 if isinstance(data, Unset): 262 return data 263 try: 264 if not isinstance(data, str): 265 raise TypeError() 266 data_from_type_0 = isoparse(data) 267 268 return data_from_type_0 269 except (TypeError, ValueError, AttributeError, KeyError): 270 pass 271 return cast(datetime.datetime | None | Unset, data) 272 273 data_from = _parse_data_from(d.pop("dataFrom", UNSET)) 274 275 def _parse_data_to(data: object) -> datetime.datetime | None | Unset: 276 if data is None: 277 return data 278 if isinstance(data, Unset): 279 return data 280 try: 281 if not isinstance(data, str): 282 raise TypeError() 283 data_to_type_0 = isoparse(data) 284 285 return data_to_type_0 286 except (TypeError, ValueError, AttributeError, KeyError): 287 pass 288 return cast(datetime.datetime | None | Unset, data) 289 290 data_to = _parse_data_to(d.pop("dataTo", UNSET)) 291 292 coverage_ratio = d.pop("coverageRatio", UNSET) 293 294 total_hours = d.pop("totalHours", UNSET) 295 296 hours_with_data = d.pop("hoursWithData", UNSET) 297 298 cadence = d.pop("cadence", UNSET) 299 300 gaps = d.pop("gaps", UNSET) 301 302 largest_gap_steps = d.pop("largestGapSteps", UNSET) 303 304 _hours_without_data = d.pop("hoursWithoutData", UNSET) 305 hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | Unset = UNSET 306 if _hours_without_data is not UNSET: 307 hours_without_data = [] 308 for hours_without_data_item_data in _hours_without_data: 309 hours_without_data_item = PrepareJobStateHoursWithoutDataItem.from_dict(hours_without_data_item_data) 310 311 hours_without_data.append(hours_without_data_item) 312 313 prepare_job_state = cls( 314 context_id=context_id, 315 status=status, 316 size=size, 317 completed=completed, 318 status_detail=status_detail, 319 start_time=start_time, 320 end_time=end_time, 321 data_from=data_from, 322 data_to=data_to, 323 coverage_ratio=coverage_ratio, 324 total_hours=total_hours, 325 hours_with_data=hours_with_data, 326 cadence=cadence, 327 gaps=gaps, 328 largest_gap_steps=largest_gap_steps, 329 hours_without_data=hours_without_data, 330 ) 331 332 prepare_job_state.additional_properties = d 333 return prepare_job_state
18@_attrs_define 19class PrepareJobStateHoursWithoutDataItem: 20 """ 21 Attributes: 22 hour (datetime.datetime | Unset): The hour (UTC, hour-aligned) that has no data. Example: 2026-04-14T02:00:00Z. 23 expected (int | Unset): Expected row count for the hour (currently always 0; reserved for 24 future use). The rationale never depends on it. 25 rationale (PrepareJobStateHoursWithoutDataItemRationale | Unset): Why the hour has no data. 26 `pending_conversion`: data for this hour is 27 still being produced — a re-poll may fill it. `low_activity`: the 28 instrument did not trade that hour. `unknown`: no data to classify by. 29 Example: low_activity. 30 """ 31 32 hour: datetime.datetime | Unset = UNSET 33 expected: int | Unset = UNSET 34 rationale: PrepareJobStateHoursWithoutDataItemRationale | Unset = UNSET 35 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 36 37 def to_dict(self) -> dict[str, Any]: 38 hour: str | Unset = UNSET 39 if not isinstance(self.hour, Unset): 40 hour = self.hour.isoformat() 41 42 expected = self.expected 43 44 rationale: str | Unset = UNSET 45 if not isinstance(self.rationale, Unset): 46 rationale = self.rationale.value 47 48 field_dict: dict[str, Any] = {} 49 field_dict.update(self.additional_properties) 50 field_dict.update({}) 51 if hour is not UNSET: 52 field_dict["hour"] = hour 53 if expected is not UNSET: 54 field_dict["expected"] = expected 55 if rationale is not UNSET: 56 field_dict["rationale"] = rationale 57 58 return field_dict 59 60 @classmethod 61 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 62 d = dict(src_dict) 63 _hour = d.pop("hour", UNSET) 64 hour: datetime.datetime | Unset 65 if isinstance(_hour, Unset): 66 hour = UNSET 67 else: 68 hour = isoparse(_hour) 69 70 expected = d.pop("expected", UNSET) 71 72 _rationale = d.pop("rationale", UNSET) 73 rationale: PrepareJobStateHoursWithoutDataItemRationale | Unset 74 if isinstance(_rationale, Unset): 75 rationale = UNSET 76 else: 77 rationale = PrepareJobStateHoursWithoutDataItemRationale(_rationale) 78 79 prepare_job_state_hours_without_data_item = cls( 80 hour=hour, 81 expected=expected, 82 rationale=rationale, 83 ) 84 85 prepare_job_state_hours_without_data_item.additional_properties = d 86 return prepare_job_state_hours_without_data_item 87 88 @property 89 def additional_keys(self) -> list[str]: 90 return list(self.additional_properties.keys()) 91 92 def __getitem__(self, key: str) -> Any: 93 return self.additional_properties[key] 94 95 def __setitem__(self, key: str, value: Any) -> None: 96 self.additional_properties[key] = value 97 98 def __delitem__(self, key: str) -> None: 99 del self.additional_properties[key] 100 101 def __contains__(self, key: str) -> bool: 102 return key in self.additional_properties
Attributes:
hour (datetime.datetime | Unset): The hour (UTC, hour-aligned) that has no data. Example: 2026-04-14T02:00:00Z.
expected (int | Unset): Expected row count for the hour (currently always 0; reserved for
future use). The rationale never depends on it.
rationale (PrepareJobStateHoursWithoutDataItemRationale | Unset): Why the hour has no data.
pending_conversion: data for this hour is
still being produced — a re-poll may fill it. low_activity: the
instrument did not trade that hour. unknown: no data to classify by.
Example: low_activity.
26def __init__(self, hour=attr_dict['hour'].default, expected=attr_dict['expected'].default, rationale=attr_dict['rationale'].default): 27 self.hour = hour 28 self.expected = expected 29 self.rationale = rationale 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class PrepareJobStateHoursWithoutDataItem.
37 def to_dict(self) -> dict[str, Any]: 38 hour: str | Unset = UNSET 39 if not isinstance(self.hour, Unset): 40 hour = self.hour.isoformat() 41 42 expected = self.expected 43 44 rationale: str | Unset = UNSET 45 if not isinstance(self.rationale, Unset): 46 rationale = self.rationale.value 47 48 field_dict: dict[str, Any] = {} 49 field_dict.update(self.additional_properties) 50 field_dict.update({}) 51 if hour is not UNSET: 52 field_dict["hour"] = hour 53 if expected is not UNSET: 54 field_dict["expected"] = expected 55 if rationale is not UNSET: 56 field_dict["rationale"] = rationale 57 58 return field_dict
60 @classmethod 61 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 62 d = dict(src_dict) 63 _hour = d.pop("hour", UNSET) 64 hour: datetime.datetime | Unset 65 if isinstance(_hour, Unset): 66 hour = UNSET 67 else: 68 hour = isoparse(_hour) 69 70 expected = d.pop("expected", UNSET) 71 72 _rationale = d.pop("rationale", UNSET) 73 rationale: PrepareJobStateHoursWithoutDataItemRationale | Unset 74 if isinstance(_rationale, Unset): 75 rationale = UNSET 76 else: 77 rationale = PrepareJobStateHoursWithoutDataItemRationale(_rationale) 78 79 prepare_job_state_hours_without_data_item = cls( 80 hour=hour, 81 expected=expected, 82 rationale=rationale, 83 ) 84 85 prepare_job_state_hours_without_data_item.additional_properties = d 86 return prepare_job_state_hours_without_data_item
5class PrepareJobStateHoursWithoutDataItemRationale(str, Enum): 6 LOW_ACTIVITY = "low_activity" 7 PENDING_CONVERSION = "pending_conversion" 8 UNKNOWN = "unknown" 9 10 def __str__(self) -> str: 11 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
16@_attrs_define 17class PrepareRequest: 18 """Two shapes, chosen by the `exchangeId` path segment. Against a managed exchange, 19 `instrument` is required and `datasetId`/`datasetVersionId` are ignored. Against the 20 reserved `exchangeId: user`, send `datasetId` instead of `instrument` — `instrument` is 21 ignored there, since it comes from the dataset itself. 22 23 Example: 24 {'instrument': 'BTC/USDT', 'from': '2024-12-13T00:00:00Z', 'to': '2024-12-14T00:00:00Z', 'cadence': '1m'} 25 26 Attributes: 27 from_ (str): Start date for the preparation process. Supports the following formats: 28 - ISO-8601 (e.g. 2024-12-14T23:59:59Z) 29 - ISO DATE (e.g. 2024-12-14) 30 - BASIC ISO DATE (e.g., 20241214) 31 Example: 2024-12-13T00:00:00Z. 32 to (str): End date for the preparation process. Supports the following formats: 33 - ISO-8601 (e.g. 2024-12-14T23:59:59Z) 34 - ISO DATE (e.g. 2024-12-14) 35 - BASIC ISO DATE (e.g., 20241214) 36 Example: 2024-12-14. 37 instrument (str | Unset): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT. 38 dataset_id (str | Unset): Only for `exchangeId: user`: the id of a dataset created via `POST /datasets`, in 39 place 40 of `instrument`. Ignored against a managed exchange. 41 Example: ds_3f9a1c2e7b0d4a5f. 42 dataset_version_id (str | Unset): Only for `exchangeId: user`, and optional even then: pins a specific past 43 version of 44 the dataset instead of its current one. Defaults to the dataset's current version. 45 Example: dsv_8e2b4f19c6a03d7e. 46 cadence (PrepareRequestCadence | Unset): Output bar cadence for the prepared range. Defaults to the publisher's 47 native cadence (`1s`); coarser cadences are produced on demand via 48 resampling and stored alongside the native blob in cache. Coarser-than- 49 source values must be exact multiples of the source cadence — invalid 50 labels return `400`. 51 Default: PrepareRequestCadence.VALUE_0. 52 """ 53 54 from_: str 55 to: str 56 instrument: str | Unset = UNSET 57 dataset_id: str | Unset = UNSET 58 dataset_version_id: str | Unset = UNSET 59 cadence: PrepareRequestCadence | Unset = PrepareRequestCadence.VALUE_0 60 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 61 62 def to_dict(self) -> dict[str, Any]: 63 from_ = self.from_ 64 65 to = self.to 66 67 instrument = self.instrument 68 69 dataset_id = self.dataset_id 70 71 dataset_version_id = self.dataset_version_id 72 73 cadence: str | Unset = UNSET 74 if not isinstance(self.cadence, Unset): 75 cadence = self.cadence.value 76 77 field_dict: dict[str, Any] = {} 78 field_dict.update(self.additional_properties) 79 field_dict.update( 80 { 81 "from": from_, 82 "to": to, 83 } 84 ) 85 if instrument is not UNSET: 86 field_dict["instrument"] = instrument 87 if dataset_id is not UNSET: 88 field_dict["datasetId"] = dataset_id 89 if dataset_version_id is not UNSET: 90 field_dict["datasetVersionId"] = dataset_version_id 91 if cadence is not UNSET: 92 field_dict["cadence"] = cadence 93 94 return field_dict 95 96 @classmethod 97 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 98 d = dict(src_dict) 99 from_ = d.pop("from") 100 101 to = d.pop("to") 102 103 instrument = d.pop("instrument", UNSET) 104 105 dataset_id = d.pop("datasetId", UNSET) 106 107 dataset_version_id = d.pop("datasetVersionId", UNSET) 108 109 _cadence = d.pop("cadence", UNSET) 110 cadence: PrepareRequestCadence | Unset 111 if isinstance(_cadence, Unset): 112 cadence = UNSET 113 else: 114 cadence = PrepareRequestCadence(_cadence) 115 116 prepare_request = cls( 117 from_=from_, 118 to=to, 119 instrument=instrument, 120 dataset_id=dataset_id, 121 dataset_version_id=dataset_version_id, 122 cadence=cadence, 123 ) 124 125 prepare_request.additional_properties = d 126 return prepare_request 127 128 @property 129 def additional_keys(self) -> list[str]: 130 return list(self.additional_properties.keys()) 131 132 def __getitem__(self, key: str) -> Any: 133 return self.additional_properties[key] 134 135 def __setitem__(self, key: str, value: Any) -> None: 136 self.additional_properties[key] = value 137 138 def __delitem__(self, key: str) -> None: 139 del self.additional_properties[key] 140 141 def __contains__(self, key: str) -> bool: 142 return key in self.additional_properties
Two shapes, chosen by the exchangeId path segment. Against a managed exchange,
instrument is required and datasetId/datasetVersionId are ignored. Against the
reserved exchangeId: user, send datasetId instead of instrument — instrument is
ignored there, since it comes from the dataset itself.
Example:
{'instrument': 'BTC/USDT', 'from': '2024-12-13T00:00:00Z', 'to': '2024-12-14T00:00:00Z', 'cadence': '1m'}
Attributes:
from_ (str): Start date for the preparation process. Supports the following formats:
- ISO-8601 (e.g. 2024-12-14T23:59:59Z)
- ISO DATE (e.g. 2024-12-14)
- BASIC ISO DATE (e.g., 20241214)
Example: 2024-12-13T00:00:00Z.
to (str): End date for the preparation process. Supports the following formats:
- ISO-8601 (e.g. 2024-12-14T23:59:59Z)
- ISO DATE (e.g. 2024-12-14)
- BASIC ISO DATE (e.g., 20241214)
Example: 2024-12-14.
instrument (str | Unset): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
dataset_id (str | Unset): Only for `exchangeId: user`: the id of a dataset created via `POST /datasets`, in
place
of `instrument`. Ignored against a managed exchange.
Example: ds_3f9a1c2e7b0d4a5f.
dataset_version_id (str | Unset): Only for `exchangeId: user`, and optional even then: pins a specific past
version of
the dataset instead of its current one. Defaults to the dataset's current version.
Example: dsv_8e2b4f19c6a03d7e.
cadence (PrepareRequestCadence | Unset): Output bar cadence for the prepared range. Defaults to the publisher's
native cadence (`1s`); coarser cadences are produced on demand via
resampling and stored alongside the native blob in cache. Coarser-than-
source values must be exact multiples of the source cadence — invalid
labels return `400`.
Default: PrepareRequestCadence.VALUE_0.
29def __init__(self, from_, to, instrument=attr_dict['instrument'].default, dataset_id=attr_dict['dataset_id'].default, dataset_version_id=attr_dict['dataset_version_id'].default, cadence=attr_dict['cadence'].default): 30 self.from_ = from_ 31 self.to = to 32 self.instrument = instrument 33 self.dataset_id = dataset_id 34 self.dataset_version_id = dataset_version_id 35 self.cadence = cadence 36 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class PrepareRequest.
62 def to_dict(self) -> dict[str, Any]: 63 from_ = self.from_ 64 65 to = self.to 66 67 instrument = self.instrument 68 69 dataset_id = self.dataset_id 70 71 dataset_version_id = self.dataset_version_id 72 73 cadence: str | Unset = UNSET 74 if not isinstance(self.cadence, Unset): 75 cadence = self.cadence.value 76 77 field_dict: dict[str, Any] = {} 78 field_dict.update(self.additional_properties) 79 field_dict.update( 80 { 81 "from": from_, 82 "to": to, 83 } 84 ) 85 if instrument is not UNSET: 86 field_dict["instrument"] = instrument 87 if dataset_id is not UNSET: 88 field_dict["datasetId"] = dataset_id 89 if dataset_version_id is not UNSET: 90 field_dict["datasetVersionId"] = dataset_version_id 91 if cadence is not UNSET: 92 field_dict["cadence"] = cadence 93 94 return field_dict
96 @classmethod 97 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 98 d = dict(src_dict) 99 from_ = d.pop("from") 100 101 to = d.pop("to") 102 103 instrument = d.pop("instrument", UNSET) 104 105 dataset_id = d.pop("datasetId", UNSET) 106 107 dataset_version_id = d.pop("datasetVersionId", UNSET) 108 109 _cadence = d.pop("cadence", UNSET) 110 cadence: PrepareRequestCadence | Unset 111 if isinstance(_cadence, Unset): 112 cadence = UNSET 113 else: 114 cadence = PrepareRequestCadence(_cadence) 115 116 prepare_request = cls( 117 from_=from_, 118 to=to, 119 instrument=instrument, 120 dataset_id=dataset_id, 121 dataset_version_id=dataset_version_id, 122 cadence=cadence, 123 ) 124 125 prepare_request.additional_properties = d 126 return prepare_request
5class PrepareRequestCadence(str, Enum): 6 VALUE_0 = "1s" 7 VALUE_1 = "5s" 8 VALUE_10 = "8h" 9 VALUE_11 = "12h" 10 VALUE_12 = "1d" 11 VALUE_13 = "1w" 12 VALUE_14 = "1q" 13 VALUE_2 = "1m" 14 VALUE_3 = "3m" 15 VALUE_4 = "5m" 16 VALUE_5 = "15m" 17 VALUE_6 = "30m" 18 VALUE_7 = "1h" 19 VALUE_8 = "2h" 20 VALUE_9 = "4h" 21 22 def __str__(self) -> str: 23 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
13@_attrs_define 14class ResponseError: 15 """General response error 16 17 Attributes: 18 code (int): Status code Example: 400. 19 message (str): Error description Example: Invalid request. 20 """ 21 22 code: int 23 message: str 24 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 25 26 def to_dict(self) -> dict[str, Any]: 27 code = self.code 28 29 message = self.message 30 31 field_dict: dict[str, Any] = {} 32 field_dict.update(self.additional_properties) 33 field_dict.update( 34 { 35 "code": code, 36 "message": message, 37 } 38 ) 39 40 return field_dict 41 42 @classmethod 43 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 44 d = dict(src_dict) 45 code = d.pop("code") 46 47 message = d.pop("message") 48 49 response_error = cls( 50 code=code, 51 message=message, 52 ) 53 54 response_error.additional_properties = d 55 return response_error 56 57 @property 58 def additional_keys(self) -> list[str]: 59 return list(self.additional_properties.keys()) 60 61 def __getitem__(self, key: str) -> Any: 62 return self.additional_properties[key] 63 64 def __setitem__(self, key: str, value: Any) -> None: 65 self.additional_properties[key] = value 66 67 def __delitem__(self, key: str) -> None: 68 del self.additional_properties[key] 69 70 def __contains__(self, key: str) -> bool: 71 return key in self.additional_properties
General response error
Attributes: code (int): Status code Example: 400. message (str): Error description Example: Invalid request.
25def __init__(self, code, message): 26 self.code = code 27 self.message = message 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ResponseError.
23@_attrs_define 24class ResultMap: 25 """Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, 26 pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade. 27 When signal storage is enabled, includes signal fields described below. `notices` carries what the run had to say 28 about itself, and is absent when it had nothing. 29 30 Attributes: 31 strategy_id (str): **Not the `strategyId` you compiled with** — this is the execution context id, 32 `strategy:<user>:<strategyId>`. The compiled strategy's id is the last `:`-separated 33 segment; that, not this whole string, is what `GET /strategy/{strategyId}` takes. 34 35 Take the segment after the last `:` rather than counting from the front: the shape has 36 changed once already and callers that indexed a fixed position broke on it. 37 Example: strategy:00000000-0000-0000-0000-000000000000:2iyvtenlzh9dabqtxn7nbv. 38 instrument (str): The instrument (currency pair) that was backtested Example: BTC/USDT. 39 host_name (str | Unset): Identifier of the worker that executed the strategy. Useful when reporting issues so 40 support can correlate with logs. Example: executor10. 41 iops (float | Unset): Instrument operations per second throughput during execution Example: 123956.53. 42 notices (list[Notice] | Unset): Diagnostics the engine raised over this run, each with `provenance: execute`. 43 44 **Absent means nothing was raised.** This is the one surface where silence is a real 45 answer: the run happened, over your data, start to finish, and the engine found nothing 46 worth saying. That is not true of the compile path, where an empty list only means a 47 short synthetic series reached nothing — see `GET /strategy/{strategyId}`. 48 49 Notices are raised on failed and aborted runs too, and those are the ones most worth 50 reading: a run that produced no trades often did so for a reason stated here. 51 notices_truncated (int | Unset): How many notices were dropped past the cap of 50. Absent when none were. A 52 large value usually means one fault repeating per instrument or per parameter vector rather than 50 distinct 53 problems. Example: 3. 54 pnl_total (float | Unset): Total profit and loss in the output currency Example: 42.75. 55 pnl_total_percent (float | Unset): Total PnL as a percentage of the initial capital (`backtestFunding`). Zero 56 when `backtestFunding` is 0. Example: 42.75. 57 total_trades (int | Unset): Total number of trades executed by the strategy Example: 156. 58 win_rate (float | Unset): Percentage of profitable trades (0-100) Example: 58.33. 59 sharpe_ratio (float | Unset): Risk-adjusted return ratio (mean return / standard deviation of returns) Example: 60 1.245. 61 sortino_ratio (float | Unset): Downside risk-adjusted return ratio (mean return / downside deviation) Example: 62 1.872. 63 cagr (float | Unset): Compound Annual Growth Rate Example: 0.1534. 64 max_drawdown (float | Unset): Maximum absolute drawdown in the output currency Example: 12.5. 65 max_drawdown_percent (float | Unset): Maximum percentage drawdown from peak equity Example: 8.75. 66 equity_curve (EquityCurveResult | Unset): An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`, 67 `timestamps` + `equities` (parallel arrays) when `SHORT`. Used identically wherever a curve is returned — a 68 plain backtest's inline `equityCurve` and a sweep row's `equityCurve` are the same type. `url` is present 69 *instead of* any points when the curve is served by pointer rather than inline (a sweep row's top-N winners 70 only): `GET` it separately to fetch this exact same shape with the points populated. 71 signal_count (int | Unset): Number of signals emitted during strategy execution Example: 100000. 72 signals_id (str | Unset): Storage key for the signals file. Treat as opaque; use signalsUrl to download. 73 Example: 00000000-0000-0000-0000-000000000000/exec/binance/3vsndwikcuaatjmb83fjtl. 74 signals_url (str | Unset): HTTPS URL to download the signals Parquet file. Use signalsUpload to know when it's 75 ready. Example: 76 https://storage.qtsurfer.com/00000000-0000-0000-0000-000000000000/exec/binance/3vsndwikcuaatjmb83fjtl.parquet. 77 signals_upload (ResultMapSignalsUpload | Unset): Upload status. Done = signal file is available at signalsUrl. 78 Failed = upload error (see signalsUploadReason). Skipped = no signals emitted. Example: Done. 79 signals_uploaded_at (datetime.datetime | Unset): ISO 8601 timestamp of when the upload completed. Only present 80 when signalsUpload is Done. Example: 2026-03-18T13:21:48.170Z. 81 signals_upload_reason (str | Unset): Human-readable reason when signalsUpload is Failed or Skipped. Example: 82 signal file generation failed. 83 """ 84 85 strategy_id: str 86 instrument: str 87 host_name: str | Unset = UNSET 88 iops: float | Unset = UNSET 89 notices: list[Notice] | Unset = UNSET 90 notices_truncated: int | Unset = UNSET 91 pnl_total: float | Unset = UNSET 92 pnl_total_percent: float | Unset = UNSET 93 total_trades: int | Unset = UNSET 94 win_rate: float | Unset = UNSET 95 sharpe_ratio: float | Unset = UNSET 96 sortino_ratio: float | Unset = UNSET 97 cagr: float | Unset = UNSET 98 max_drawdown: float | Unset = UNSET 99 max_drawdown_percent: float | Unset = UNSET 100 equity_curve: EquityCurveResult | Unset = UNSET 101 signal_count: int | Unset = UNSET 102 signals_id: str | Unset = UNSET 103 signals_url: str | Unset = UNSET 104 signals_upload: ResultMapSignalsUpload | Unset = UNSET 105 signals_uploaded_at: datetime.datetime | Unset = UNSET 106 signals_upload_reason: str | Unset = UNSET 107 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 108 109 def to_dict(self) -> dict[str, Any]: 110 strategy_id = self.strategy_id 111 112 instrument = self.instrument 113 114 host_name = self.host_name 115 116 iops = self.iops 117 118 notices: list[dict[str, Any]] | Unset = UNSET 119 if not isinstance(self.notices, Unset): 120 notices = [] 121 for notices_item_data in self.notices: 122 notices_item = notices_item_data.to_dict() 123 notices.append(notices_item) 124 125 notices_truncated = self.notices_truncated 126 127 pnl_total = self.pnl_total 128 129 pnl_total_percent = self.pnl_total_percent 130 131 total_trades = self.total_trades 132 133 win_rate = self.win_rate 134 135 sharpe_ratio = self.sharpe_ratio 136 137 sortino_ratio = self.sortino_ratio 138 139 cagr = self.cagr 140 141 max_drawdown = self.max_drawdown 142 143 max_drawdown_percent = self.max_drawdown_percent 144 145 equity_curve: dict[str, Any] | Unset = UNSET 146 if not isinstance(self.equity_curve, Unset): 147 equity_curve = self.equity_curve.to_dict() 148 149 signal_count = self.signal_count 150 151 signals_id = self.signals_id 152 153 signals_url = self.signals_url 154 155 signals_upload: str | Unset = UNSET 156 if not isinstance(self.signals_upload, Unset): 157 signals_upload = self.signals_upload.value 158 159 signals_uploaded_at: str | Unset = UNSET 160 if not isinstance(self.signals_uploaded_at, Unset): 161 signals_uploaded_at = self.signals_uploaded_at.isoformat() 162 163 signals_upload_reason = self.signals_upload_reason 164 165 field_dict: dict[str, Any] = {} 166 field_dict.update(self.additional_properties) 167 field_dict.update( 168 { 169 "strategyId": strategy_id, 170 "instrument": instrument, 171 } 172 ) 173 if host_name is not UNSET: 174 field_dict["hostName"] = host_name 175 if iops is not UNSET: 176 field_dict["iops"] = iops 177 if notices is not UNSET: 178 field_dict["notices"] = notices 179 if notices_truncated is not UNSET: 180 field_dict["noticesTruncated"] = notices_truncated 181 if pnl_total is not UNSET: 182 field_dict["pnlTotal"] = pnl_total 183 if pnl_total_percent is not UNSET: 184 field_dict["pnlTotalPercent"] = pnl_total_percent 185 if total_trades is not UNSET: 186 field_dict["totalTrades"] = total_trades 187 if win_rate is not UNSET: 188 field_dict["winRate"] = win_rate 189 if sharpe_ratio is not UNSET: 190 field_dict["sharpeRatio"] = sharpe_ratio 191 if sortino_ratio is not UNSET: 192 field_dict["sortinoRatio"] = sortino_ratio 193 if cagr is not UNSET: 194 field_dict["cagr"] = cagr 195 if max_drawdown is not UNSET: 196 field_dict["maxDrawdown"] = max_drawdown 197 if max_drawdown_percent is not UNSET: 198 field_dict["maxDrawdownPercent"] = max_drawdown_percent 199 if equity_curve is not UNSET: 200 field_dict["equityCurve"] = equity_curve 201 if signal_count is not UNSET: 202 field_dict["signalCount"] = signal_count 203 if signals_id is not UNSET: 204 field_dict["signalsId"] = signals_id 205 if signals_url is not UNSET: 206 field_dict["signalsUrl"] = signals_url 207 if signals_upload is not UNSET: 208 field_dict["signalsUpload"] = signals_upload 209 if signals_uploaded_at is not UNSET: 210 field_dict["signalsUploadedAt"] = signals_uploaded_at 211 if signals_upload_reason is not UNSET: 212 field_dict["signalsUploadReason"] = signals_upload_reason 213 214 return field_dict 215 216 @classmethod 217 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 218 from ..models.equity_curve_result import EquityCurveResult 219 from ..models.notice import Notice 220 221 d = dict(src_dict) 222 strategy_id = d.pop("strategyId") 223 224 instrument = d.pop("instrument") 225 226 host_name = d.pop("hostName", UNSET) 227 228 iops = d.pop("iops", UNSET) 229 230 _notices = d.pop("notices", UNSET) 231 notices: list[Notice] | Unset = UNSET 232 if _notices is not UNSET: 233 notices = [] 234 for notices_item_data in _notices: 235 notices_item = Notice.from_dict(notices_item_data) 236 237 notices.append(notices_item) 238 239 notices_truncated = d.pop("noticesTruncated", UNSET) 240 241 pnl_total = d.pop("pnlTotal", UNSET) 242 243 pnl_total_percent = d.pop("pnlTotalPercent", UNSET) 244 245 total_trades = d.pop("totalTrades", UNSET) 246 247 win_rate = d.pop("winRate", UNSET) 248 249 sharpe_ratio = d.pop("sharpeRatio", UNSET) 250 251 sortino_ratio = d.pop("sortinoRatio", UNSET) 252 253 cagr = d.pop("cagr", UNSET) 254 255 max_drawdown = d.pop("maxDrawdown", UNSET) 256 257 max_drawdown_percent = d.pop("maxDrawdownPercent", UNSET) 258 259 _equity_curve = d.pop("equityCurve", UNSET) 260 equity_curve: EquityCurveResult | Unset 261 if isinstance(_equity_curve, Unset): 262 equity_curve = UNSET 263 else: 264 equity_curve = EquityCurveResult.from_dict(_equity_curve) 265 266 signal_count = d.pop("signalCount", UNSET) 267 268 signals_id = d.pop("signalsId", UNSET) 269 270 signals_url = d.pop("signalsUrl", UNSET) 271 272 _signals_upload = d.pop("signalsUpload", UNSET) 273 signals_upload: ResultMapSignalsUpload | Unset 274 if isinstance(_signals_upload, Unset): 275 signals_upload = UNSET 276 else: 277 signals_upload = ResultMapSignalsUpload(_signals_upload) 278 279 _signals_uploaded_at = d.pop("signalsUploadedAt", UNSET) 280 signals_uploaded_at: datetime.datetime | Unset 281 if isinstance(_signals_uploaded_at, Unset): 282 signals_uploaded_at = UNSET 283 else: 284 signals_uploaded_at = isoparse(_signals_uploaded_at) 285 286 signals_upload_reason = d.pop("signalsUploadReason", UNSET) 287 288 result_map = cls( 289 strategy_id=strategy_id, 290 instrument=instrument, 291 host_name=host_name, 292 iops=iops, 293 notices=notices, 294 notices_truncated=notices_truncated, 295 pnl_total=pnl_total, 296 pnl_total_percent=pnl_total_percent, 297 total_trades=total_trades, 298 win_rate=win_rate, 299 sharpe_ratio=sharpe_ratio, 300 sortino_ratio=sortino_ratio, 301 cagr=cagr, 302 max_drawdown=max_drawdown, 303 max_drawdown_percent=max_drawdown_percent, 304 equity_curve=equity_curve, 305 signal_count=signal_count, 306 signals_id=signals_id, 307 signals_url=signals_url, 308 signals_upload=signals_upload, 309 signals_uploaded_at=signals_uploaded_at, 310 signals_upload_reason=signals_upload_reason, 311 ) 312 313 result_map.additional_properties = d 314 return result_map 315 316 @property 317 def additional_keys(self) -> list[str]: 318 return list(self.additional_properties.keys()) 319 320 def __getitem__(self, key: str) -> Any: 321 return self.additional_properties[key] 322 323 def __setitem__(self, key: str, value: Any) -> None: 324 self.additional_properties[key] = value 325 326 def __delitem__(self, key: str) -> None: 327 del self.additional_properties[key] 328 329 def __contains__(self, key: str) -> bool: 330 return key in self.additional_properties
Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal,
pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade.
When signal storage is enabled, includes signal fields described below. notices carries what the run had to say
about itself, and is absent when it had nothing.
Attributes:
strategy_id (str): **Not the `strategyId` you compiled with** — this is the execution context id,
`strategy:<user>:<strategyId>`. The compiled strategy's id is the last `:`-separated
segment; that, not this whole string, is what `GET /strategy/{strategyId}` takes.
Take the segment after the last `:` rather than counting from the front: the shape has
changed once already and callers that indexed a fixed position broke on it.
Example: strategy:00000000-0000-0000-0000-000000000000:2iyvtenlzh9dabqtxn7nbv.
instrument (str): The instrument (currency pair) that was backtested Example: BTC/USDT.
host_name (str | Unset): Identifier of the worker that executed the strategy. Useful when reporting issues so
support can correlate with logs. Example: executor10.
iops (float | Unset): Instrument operations per second throughput during execution Example: 123956.53.
notices (list[Notice] | Unset): Diagnostics the engine raised over this run, each with `provenance: execute`.
**Absent means nothing was raised.** This is the one surface where silence is a real
answer: the run happened, over your data, start to finish, and the engine found nothing
worth saying. That is not true of the compile path, where an empty list only means a
short synthetic series reached nothing — see `GET /strategy/{strategyId}`.
Notices are raised on failed and aborted runs too, and those are the ones most worth
reading: a run that produced no trades often did so for a reason stated here.
notices_truncated (int | Unset): How many notices were dropped past the cap of 50. Absent when none were. A
large value usually means one fault repeating per instrument or per parameter vector rather than 50 distinct
problems. Example: 3.
pnl_total (float | Unset): Total profit and loss in the output currency Example: 42.75.
pnl_total_percent (float | Unset): Total PnL as a percentage of the initial capital (`backtestFunding`). Zero
when `backtestFunding` is 0. Example: 42.75.
total_trades (int | Unset): Total number of trades executed by the strategy Example: 156.
win_rate (float | Unset): Percentage of profitable trades (0-100) Example: 58.33.
sharpe_ratio (float | Unset): Risk-adjusted return ratio (mean return / standard deviation of returns) Example:
1.245.
sortino_ratio (float | Unset): Downside risk-adjusted return ratio (mean return / downside deviation) Example:
1.872.
cagr (float | Unset): Compound Annual Growth Rate Example: 0.1534.
max_drawdown (float | Unset): Maximum absolute drawdown in the output currency Example: 12.5.
max_drawdown_percent (float | Unset): Maximum percentage drawdown from peak equity Example: 8.75.
equity_curve (EquityCurveResult | Unset): An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`,
`timestamps` + `equities` (parallel arrays) when `SHORT`. Used identically wherever a curve is returned — a
plain backtest's inline `equityCurve` and a sweep row's `equityCurve` are the same type. `url` is present
*instead of* any points when the curve is served by pointer rather than inline (a sweep row's top-N winners
only): `GET` it separately to fetch this exact same shape with the points populated.
signal_count (int | Unset): Number of signals emitted during strategy execution Example: 100000.
signals_id (str | Unset): Storage key for the signals file. Treat as opaque; use signalsUrl to download.
Example: 00000000-0000-0000-0000-000000000000/exec/binance/3vsndwikcuaatjmb83fjtl.
signals_url (str | Unset): HTTPS URL to download the signals Parquet file. Use signalsUpload to know when it's
ready. Example:
https://storage.qtsurfer.com/00000000-0000-0000-0000-000000000000/exec/binance/3vsndwikcuaatjmb83fjtl.parquet.
signals_upload (ResultMapSignalsUpload | Unset): Upload status. Done = signal file is available at signalsUrl.
Failed = upload error (see signalsUploadReason). Skipped = no signals emitted. Example: Done.
signals_uploaded_at (datetime.datetime | Unset): ISO 8601 timestamp of when the upload completed. Only present
when signalsUpload is Done. Example: 2026-03-18T13:21:48.170Z.
signals_upload_reason (str | Unset): Human-readable reason when signalsUpload is Failed or Skipped. Example:
signal file generation failed.
45def __init__(self, strategy_id, instrument, host_name=attr_dict['host_name'].default, iops=attr_dict['iops'].default, notices=attr_dict['notices'].default, notices_truncated=attr_dict['notices_truncated'].default, pnl_total=attr_dict['pnl_total'].default, pnl_total_percent=attr_dict['pnl_total_percent'].default, total_trades=attr_dict['total_trades'].default, win_rate=attr_dict['win_rate'].default, sharpe_ratio=attr_dict['sharpe_ratio'].default, sortino_ratio=attr_dict['sortino_ratio'].default, cagr=attr_dict['cagr'].default, max_drawdown=attr_dict['max_drawdown'].default, max_drawdown_percent=attr_dict['max_drawdown_percent'].default, equity_curve=attr_dict['equity_curve'].default, signal_count=attr_dict['signal_count'].default, signals_id=attr_dict['signals_id'].default, signals_url=attr_dict['signals_url'].default, signals_upload=attr_dict['signals_upload'].default, signals_uploaded_at=attr_dict['signals_uploaded_at'].default, signals_upload_reason=attr_dict['signals_upload_reason'].default): 46 self.strategy_id = strategy_id 47 self.instrument = instrument 48 self.host_name = host_name 49 self.iops = iops 50 self.notices = notices 51 self.notices_truncated = notices_truncated 52 self.pnl_total = pnl_total 53 self.pnl_total_percent = pnl_total_percent 54 self.total_trades = total_trades 55 self.win_rate = win_rate 56 self.sharpe_ratio = sharpe_ratio 57 self.sortino_ratio = sortino_ratio 58 self.cagr = cagr 59 self.max_drawdown = max_drawdown 60 self.max_drawdown_percent = max_drawdown_percent 61 self.equity_curve = equity_curve 62 self.signal_count = signal_count 63 self.signals_id = signals_id 64 self.signals_url = signals_url 65 self.signals_upload = signals_upload 66 self.signals_uploaded_at = signals_uploaded_at 67 self.signals_upload_reason = signals_upload_reason 68 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class ResultMap.
109 def to_dict(self) -> dict[str, Any]: 110 strategy_id = self.strategy_id 111 112 instrument = self.instrument 113 114 host_name = self.host_name 115 116 iops = self.iops 117 118 notices: list[dict[str, Any]] | Unset = UNSET 119 if not isinstance(self.notices, Unset): 120 notices = [] 121 for notices_item_data in self.notices: 122 notices_item = notices_item_data.to_dict() 123 notices.append(notices_item) 124 125 notices_truncated = self.notices_truncated 126 127 pnl_total = self.pnl_total 128 129 pnl_total_percent = self.pnl_total_percent 130 131 total_trades = self.total_trades 132 133 win_rate = self.win_rate 134 135 sharpe_ratio = self.sharpe_ratio 136 137 sortino_ratio = self.sortino_ratio 138 139 cagr = self.cagr 140 141 max_drawdown = self.max_drawdown 142 143 max_drawdown_percent = self.max_drawdown_percent 144 145 equity_curve: dict[str, Any] | Unset = UNSET 146 if not isinstance(self.equity_curve, Unset): 147 equity_curve = self.equity_curve.to_dict() 148 149 signal_count = self.signal_count 150 151 signals_id = self.signals_id 152 153 signals_url = self.signals_url 154 155 signals_upload: str | Unset = UNSET 156 if not isinstance(self.signals_upload, Unset): 157 signals_upload = self.signals_upload.value 158 159 signals_uploaded_at: str | Unset = UNSET 160 if not isinstance(self.signals_uploaded_at, Unset): 161 signals_uploaded_at = self.signals_uploaded_at.isoformat() 162 163 signals_upload_reason = self.signals_upload_reason 164 165 field_dict: dict[str, Any] = {} 166 field_dict.update(self.additional_properties) 167 field_dict.update( 168 { 169 "strategyId": strategy_id, 170 "instrument": instrument, 171 } 172 ) 173 if host_name is not UNSET: 174 field_dict["hostName"] = host_name 175 if iops is not UNSET: 176 field_dict["iops"] = iops 177 if notices is not UNSET: 178 field_dict["notices"] = notices 179 if notices_truncated is not UNSET: 180 field_dict["noticesTruncated"] = notices_truncated 181 if pnl_total is not UNSET: 182 field_dict["pnlTotal"] = pnl_total 183 if pnl_total_percent is not UNSET: 184 field_dict["pnlTotalPercent"] = pnl_total_percent 185 if total_trades is not UNSET: 186 field_dict["totalTrades"] = total_trades 187 if win_rate is not UNSET: 188 field_dict["winRate"] = win_rate 189 if sharpe_ratio is not UNSET: 190 field_dict["sharpeRatio"] = sharpe_ratio 191 if sortino_ratio is not UNSET: 192 field_dict["sortinoRatio"] = sortino_ratio 193 if cagr is not UNSET: 194 field_dict["cagr"] = cagr 195 if max_drawdown is not UNSET: 196 field_dict["maxDrawdown"] = max_drawdown 197 if max_drawdown_percent is not UNSET: 198 field_dict["maxDrawdownPercent"] = max_drawdown_percent 199 if equity_curve is not UNSET: 200 field_dict["equityCurve"] = equity_curve 201 if signal_count is not UNSET: 202 field_dict["signalCount"] = signal_count 203 if signals_id is not UNSET: 204 field_dict["signalsId"] = signals_id 205 if signals_url is not UNSET: 206 field_dict["signalsUrl"] = signals_url 207 if signals_upload is not UNSET: 208 field_dict["signalsUpload"] = signals_upload 209 if signals_uploaded_at is not UNSET: 210 field_dict["signalsUploadedAt"] = signals_uploaded_at 211 if signals_upload_reason is not UNSET: 212 field_dict["signalsUploadReason"] = signals_upload_reason 213 214 return field_dict
216 @classmethod 217 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 218 from ..models.equity_curve_result import EquityCurveResult 219 from ..models.notice import Notice 220 221 d = dict(src_dict) 222 strategy_id = d.pop("strategyId") 223 224 instrument = d.pop("instrument") 225 226 host_name = d.pop("hostName", UNSET) 227 228 iops = d.pop("iops", UNSET) 229 230 _notices = d.pop("notices", UNSET) 231 notices: list[Notice] | Unset = UNSET 232 if _notices is not UNSET: 233 notices = [] 234 for notices_item_data in _notices: 235 notices_item = Notice.from_dict(notices_item_data) 236 237 notices.append(notices_item) 238 239 notices_truncated = d.pop("noticesTruncated", UNSET) 240 241 pnl_total = d.pop("pnlTotal", UNSET) 242 243 pnl_total_percent = d.pop("pnlTotalPercent", UNSET) 244 245 total_trades = d.pop("totalTrades", UNSET) 246 247 win_rate = d.pop("winRate", UNSET) 248 249 sharpe_ratio = d.pop("sharpeRatio", UNSET) 250 251 sortino_ratio = d.pop("sortinoRatio", UNSET) 252 253 cagr = d.pop("cagr", UNSET) 254 255 max_drawdown = d.pop("maxDrawdown", UNSET) 256 257 max_drawdown_percent = d.pop("maxDrawdownPercent", UNSET) 258 259 _equity_curve = d.pop("equityCurve", UNSET) 260 equity_curve: EquityCurveResult | Unset 261 if isinstance(_equity_curve, Unset): 262 equity_curve = UNSET 263 else: 264 equity_curve = EquityCurveResult.from_dict(_equity_curve) 265 266 signal_count = d.pop("signalCount", UNSET) 267 268 signals_id = d.pop("signalsId", UNSET) 269 270 signals_url = d.pop("signalsUrl", UNSET) 271 272 _signals_upload = d.pop("signalsUpload", UNSET) 273 signals_upload: ResultMapSignalsUpload | Unset 274 if isinstance(_signals_upload, Unset): 275 signals_upload = UNSET 276 else: 277 signals_upload = ResultMapSignalsUpload(_signals_upload) 278 279 _signals_uploaded_at = d.pop("signalsUploadedAt", UNSET) 280 signals_uploaded_at: datetime.datetime | Unset 281 if isinstance(_signals_uploaded_at, Unset): 282 signals_uploaded_at = UNSET 283 else: 284 signals_uploaded_at = isoparse(_signals_uploaded_at) 285 286 signals_upload_reason = d.pop("signalsUploadReason", UNSET) 287 288 result_map = cls( 289 strategy_id=strategy_id, 290 instrument=instrument, 291 host_name=host_name, 292 iops=iops, 293 notices=notices, 294 notices_truncated=notices_truncated, 295 pnl_total=pnl_total, 296 pnl_total_percent=pnl_total_percent, 297 total_trades=total_trades, 298 win_rate=win_rate, 299 sharpe_ratio=sharpe_ratio, 300 sortino_ratio=sortino_ratio, 301 cagr=cagr, 302 max_drawdown=max_drawdown, 303 max_drawdown_percent=max_drawdown_percent, 304 equity_curve=equity_curve, 305 signal_count=signal_count, 306 signals_id=signals_id, 307 signals_url=signals_url, 308 signals_upload=signals_upload, 309 signals_uploaded_at=signals_uploaded_at, 310 signals_upload_reason=signals_upload_reason, 311 ) 312 313 result_map.additional_properties = d 314 return result_map
5class ResultMapSignalsUpload(str, Enum): 6 DONE = "Done" 7 FAILED = "Failed" 8 SKIPPED = "Skipped" 9 10 def __str__(self) -> str: 11 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class StrategyLinks: 19 """HAL `_links` for a strategy — present on a full `StrategyState` body (`GET 20 /strategy/{strategyId}`, and `POST /strategy/{strategyId}/validate`'s already-validated 21 `200`), absent from that same endpoint's `202` — a deliberately partial stub carrying only 22 what is known before a check has even started. Following `code` can still `404` once 23 present: it documents its own honest "nothing to return" for a strategy with no source of 24 its own (a `REFERENCE` marketplace copy, or one resolved only through the platform's shared 25 pool). This link says where to look, not that something is there. 26 27 Attributes: 28 code (HalLink): A HAL link object (Hypertext Application Language) 29 """ 30 31 code: HalLink 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 code = self.code.to_dict() 36 37 field_dict: dict[str, Any] = {} 38 field_dict.update(self.additional_properties) 39 field_dict.update( 40 { 41 "code": code, 42 } 43 ) 44 45 return field_dict 46 47 @classmethod 48 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 49 from ..models.hal_link import HalLink 50 51 d = dict(src_dict) 52 code = HalLink.from_dict(d.pop("code")) 53 54 strategy_links = cls( 55 code=code, 56 ) 57 58 strategy_links.additional_properties = d 59 return strategy_links 60 61 @property 62 def additional_keys(self) -> list[str]: 63 return list(self.additional_properties.keys()) 64 65 def __getitem__(self, key: str) -> Any: 66 return self.additional_properties[key] 67 68 def __setitem__(self, key: str, value: Any) -> None: 69 self.additional_properties[key] = value 70 71 def __delitem__(self, key: str) -> None: 72 del self.additional_properties[key] 73 74 def __contains__(self, key: str) -> bool: 75 return key in self.additional_properties
HAL _links for a strategy — present on a full StrategyState body (GET
/strategy/{strategyId}, and POST /strategy/{strategyId}/validate's already-validated
200), absent from that same endpoint's 202 — a deliberately partial stub carrying only
what is known before a check has even started. Following code can still 404 once
present: it documents its own honest "nothing to return" for a strategy with no source of
its own (a REFERENCE marketplace copy, or one resolved only through the platform's shared
pool). This link says where to look, not that something is there.
Attributes:
code (HalLink): A HAL link object (Hypertext Application Language)
24def __init__(self, code): 25 self.code = code 26 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class StrategyLinks.
47 @classmethod 48 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 49 from ..models.hal_link import HalLink 50 51 d = dict(src_dict) 52 code = HalLink.from_dict(d.pop("code")) 53 54 strategy_links = cls( 55 code=code, 56 ) 57 58 strategy_links.additional_properties = d 59 return strategy_links
24@_attrs_define 25class StrategyState: 26 """What is known about a registered strategy: that it compiled, and what validating it found. 27 28 **`validation: passed` does not mean the strategy is correct.** It means the class loaded and 29 survived the first event of a short synthetic run — a floor, not a guarantee. When 30 `dryRunIncomplete` is true it is a lower floor still, because the run did not finish. 31 32 Example: 33 {'strategyId': '6bsh31ikwkuivhtgcoa6s4', 'validation': 'passed', 'compiledAt': '2026-08-04T16:23:04Z', 34 'requiredSources': ['Ticker'], 'validatedAt': '2026-08-04T16:24:11Z', 'notices': [{'level': 'WARN', 'code': 35 'indicator.bar-data-on-ticker-path', 'message': 'Indicator requires bar data but is on the ticker path', 36 'provenance': 'compile-dry-run'}], '_links': {'code': {'href': '/v1/strategy/6bsh31ikwkuivhtgcoa6s4/code'}}} 37 38 Attributes: 39 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 40 always yields the same id, for every caller, whatever its formatting. See 41 `POST /strategy` for exactly which rewrites preserve it and which do not. 42 Example: 6bsh31ikwkuivhtgcoa6s4. 43 validation (StrategyStateValidation): * `not_validated` — registered, never checked. `POST 44 /strategy/{strategyId}/validate` 45 checks it. 46 * `pending` — a check was asked for and has not answered yet. 47 * `passed` — the class loaded and survived its first event. 48 * `failed` — it did not; `detail` says how. 49 Example: passed. 50 compiled_at (datetime.datetime | Unset): When the live compilation was produced. 51 required_sources (list[StrategyStateRequiredSourcesItem] | Unset): The market data a strategy needs, read off 52 the compiled class rather than off anything 53 you sent — `TickerStrategy`, `KlineStrategy` and `FundingRateStrategy` each declare one, 54 and a `MultiSourceStrategy` declares a set. 55 56 **Absent is not "needs nothing".** A strategy always needs market data, so an absent 57 field never means an empty requirement — it means the platform could not establish the 58 answer without constructing your strategy, which it will not do to fill in a field. 59 That happens for a `MultiSourceStrategy`, for a class that overrides 60 `getMarketDataSource()`, and for anything registered before this field existed; 61 re-registering the source fills it in. 62 Example: ['Ticker']. 63 validated_at (datetime.datetime | Unset): When the verdict was recorded. Absent until there is one. 64 detail (str | Unset): Why validation failed, or why a queued check has not reported. Present on `failed`, and 65 alongside `validationStalled`. 66 notices (list[Notice] | Unset): What the run surfaced. An empty or absent list is not a clean bill of health 67 when 68 `dryRunIncomplete` is true — see that field. 69 notices_truncated (int | Unset): How many notices were dropped past the cap. Absent when none were. Example: 3. 70 dry_run_incomplete (bool | Unset): The check did not finish its budget — it ran out of time, was refused because 71 the 72 platform was already holding too many unfinishable runs, or hit a failure attributable to 73 the synthetic instrument rather than to your strategy. The verdict stands as far as it 74 went; it simply reached less than a full run would. 75 validation_stalled (bool | Unset): A queued check has not reported for far longer than one takes. Nothing is 76 disproved about 77 the strategy — the check has not run. Stop waiting and re-request it later. 78 field_links (StrategyLinks | Unset): HAL `_links` for a strategy — present on a full `StrategyState` body (`GET 79 /strategy/{strategyId}`, and `POST /strategy/{strategyId}/validate`'s already-validated 80 `200`), absent from that same endpoint's `202` — a deliberately partial stub carrying only 81 what is known before a check has even started. Following `code` can still `404` once 82 present: it documents its own honest "nothing to return" for a strategy with no source of 83 its own (a `REFERENCE` marketplace copy, or one resolved only through the platform's shared 84 pool). This link says where to look, not that something is there. 85 """ 86 87 strategy_id: str 88 validation: StrategyStateValidation 89 compiled_at: datetime.datetime | Unset = UNSET 90 required_sources: list[StrategyStateRequiredSourcesItem] | Unset = UNSET 91 validated_at: datetime.datetime | Unset = UNSET 92 detail: str | Unset = UNSET 93 notices: list[Notice] | Unset = UNSET 94 notices_truncated: int | Unset = UNSET 95 dry_run_incomplete: bool | Unset = UNSET 96 validation_stalled: bool | Unset = UNSET 97 field_links: StrategyLinks | Unset = UNSET 98 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 99 100 def to_dict(self) -> dict[str, Any]: 101 strategy_id = self.strategy_id 102 103 validation = self.validation.value 104 105 compiled_at: str | Unset = UNSET 106 if not isinstance(self.compiled_at, Unset): 107 compiled_at = self.compiled_at.isoformat() 108 109 required_sources: list[str] | Unset = UNSET 110 if not isinstance(self.required_sources, Unset): 111 required_sources = [] 112 for required_sources_item_data in self.required_sources: 113 required_sources_item = required_sources_item_data.value 114 required_sources.append(required_sources_item) 115 116 validated_at: str | Unset = UNSET 117 if not isinstance(self.validated_at, Unset): 118 validated_at = self.validated_at.isoformat() 119 120 detail = self.detail 121 122 notices: list[dict[str, Any]] | Unset = UNSET 123 if not isinstance(self.notices, Unset): 124 notices = [] 125 for notices_item_data in self.notices: 126 notices_item = notices_item_data.to_dict() 127 notices.append(notices_item) 128 129 notices_truncated = self.notices_truncated 130 131 dry_run_incomplete = self.dry_run_incomplete 132 133 validation_stalled = self.validation_stalled 134 135 field_links: dict[str, Any] | Unset = UNSET 136 if not isinstance(self.field_links, Unset): 137 field_links = self.field_links.to_dict() 138 139 field_dict: dict[str, Any] = {} 140 field_dict.update(self.additional_properties) 141 field_dict.update( 142 { 143 "strategyId": strategy_id, 144 "validation": validation, 145 } 146 ) 147 if compiled_at is not UNSET: 148 field_dict["compiledAt"] = compiled_at 149 if required_sources is not UNSET: 150 field_dict["requiredSources"] = required_sources 151 if validated_at is not UNSET: 152 field_dict["validatedAt"] = validated_at 153 if detail is not UNSET: 154 field_dict["detail"] = detail 155 if notices is not UNSET: 156 field_dict["notices"] = notices 157 if notices_truncated is not UNSET: 158 field_dict["noticesTruncated"] = notices_truncated 159 if dry_run_incomplete is not UNSET: 160 field_dict["dryRunIncomplete"] = dry_run_incomplete 161 if validation_stalled is not UNSET: 162 field_dict["validationStalled"] = validation_stalled 163 if field_links is not UNSET: 164 field_dict["_links"] = field_links 165 166 return field_dict 167 168 @classmethod 169 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 170 from ..models.notice import Notice 171 from ..models.strategy_links import StrategyLinks 172 173 d = dict(src_dict) 174 strategy_id = d.pop("strategyId") 175 176 validation = StrategyStateValidation(d.pop("validation")) 177 178 _compiled_at = d.pop("compiledAt", UNSET) 179 compiled_at: datetime.datetime | Unset 180 if isinstance(_compiled_at, Unset): 181 compiled_at = UNSET 182 else: 183 compiled_at = isoparse(_compiled_at) 184 185 _required_sources = d.pop("requiredSources", UNSET) 186 required_sources: list[StrategyStateRequiredSourcesItem] | Unset = UNSET 187 if _required_sources is not UNSET: 188 required_sources = [] 189 for required_sources_item_data in _required_sources: 190 required_sources_item = StrategyStateRequiredSourcesItem(required_sources_item_data) 191 192 required_sources.append(required_sources_item) 193 194 _validated_at = d.pop("validatedAt", UNSET) 195 validated_at: datetime.datetime | Unset 196 if isinstance(_validated_at, Unset): 197 validated_at = UNSET 198 else: 199 validated_at = isoparse(_validated_at) 200 201 detail = d.pop("detail", UNSET) 202 203 _notices = d.pop("notices", UNSET) 204 notices: list[Notice] | Unset = UNSET 205 if _notices is not UNSET: 206 notices = [] 207 for notices_item_data in _notices: 208 notices_item = Notice.from_dict(notices_item_data) 209 210 notices.append(notices_item) 211 212 notices_truncated = d.pop("noticesTruncated", UNSET) 213 214 dry_run_incomplete = d.pop("dryRunIncomplete", UNSET) 215 216 validation_stalled = d.pop("validationStalled", UNSET) 217 218 _field_links = d.pop("_links", UNSET) 219 field_links: StrategyLinks | Unset 220 if isinstance(_field_links, Unset): 221 field_links = UNSET 222 else: 223 field_links = StrategyLinks.from_dict(_field_links) 224 225 strategy_state = cls( 226 strategy_id=strategy_id, 227 validation=validation, 228 compiled_at=compiled_at, 229 required_sources=required_sources, 230 validated_at=validated_at, 231 detail=detail, 232 notices=notices, 233 notices_truncated=notices_truncated, 234 dry_run_incomplete=dry_run_incomplete, 235 validation_stalled=validation_stalled, 236 field_links=field_links, 237 ) 238 239 strategy_state.additional_properties = d 240 return strategy_state 241 242 @property 243 def additional_keys(self) -> list[str]: 244 return list(self.additional_properties.keys()) 245 246 def __getitem__(self, key: str) -> Any: 247 return self.additional_properties[key] 248 249 def __setitem__(self, key: str, value: Any) -> None: 250 self.additional_properties[key] = value 251 252 def __delitem__(self, key: str) -> None: 253 del self.additional_properties[key] 254 255 def __contains__(self, key: str) -> bool: 256 return key in self.additional_properties
What is known about a registered strategy: that it compiled, and what validating it found.
validation: passed does not mean the strategy is correct. It means the class loaded and
survived the first event of a short synthetic run — a floor, not a guarantee. When
dryRunIncomplete is true it is a lower floor still, because the run did not finish.
Example:
{'strategyId': '6bsh31ikwkuivhtgcoa6s4', 'validation': 'passed', 'compiledAt': '2026-08-04T16:23:04Z',
'requiredSources': ['Ticker'], 'validatedAt': '2026-08-04T16:24:11Z', 'notices': [{'level': 'WARN', 'code':
'indicator.bar-data-on-ticker-path', 'message': 'Indicator requires bar data but is on the ticker path',
'provenance': 'compile-dry-run'}], '_links': {'code': {'href': '/v1/strategy/6bsh31ikwkuivhtgcoa6s4/code'}}}
Attributes:
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
`POST /strategy` for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
validation (StrategyStateValidation): * `not_validated` — registered, never checked. `POST
/strategy/{strategyId}/validate`
checks it.
* `pending` — a check was asked for and has not answered yet.
* `passed` — the class loaded and survived its first event.
* `failed` — it did not; `detail` says how.
Example: passed.
compiled_at (datetime.datetime | Unset): When the live compilation was produced.
required_sources (list[StrategyStateRequiredSourcesItem] | Unset): The market data a strategy needs, read off
the compiled class rather than off anything
you sent — `TickerStrategy`, `KlineStrategy` and `FundingRateStrategy` each declare one,
and a `MultiSourceStrategy` declares a set.
**Absent is not "needs nothing".** A strategy always needs market data, so an absent
field never means an empty requirement — it means the platform could not establish the
answer without constructing your strategy, which it will not do to fill in a field.
That happens for a `MultiSourceStrategy`, for a class that overrides
`getMarketDataSource()`, and for anything registered before this field existed;
re-registering the source fills it in.
Example: ['Ticker'].
validated_at (datetime.datetime | Unset): When the verdict was recorded. Absent until there is one.
detail (str | Unset): Why validation failed, or why a queued check has not reported. Present on `failed`, and
alongside `validationStalled`.
notices (list[Notice] | Unset): What the run surfaced. An empty or absent list is not a clean bill of health
when
`dryRunIncomplete` is true — see that field.
notices_truncated (int | Unset): How many notices were dropped past the cap. Absent when none were. Example: 3.
dry_run_incomplete (bool | Unset): The check did not finish its budget — it ran out of time, was refused because
the
platform was already holding too many unfinishable runs, or hit a failure attributable to
the synthetic instrument rather than to your strategy. The verdict stands as far as it
went; it simply reached less than a full run would.
validation_stalled (bool | Unset): A queued check has not reported for far longer than one takes. Nothing is
disproved about
the strategy — the check has not run. Stop waiting and re-request it later.
field_links (StrategyLinks | Unset): HAL `_links` for a strategy — present on a full `StrategyState` body (`GET
/strategy/{strategyId}`, and `POST /strategy/{strategyId}/validate`'s already-validated
`200`), absent from that same endpoint's `202` — a deliberately partial stub carrying only
what is known before a check has even started. Following `code` can still `404` once
present: it documents its own honest "nothing to return" for a strategy with no source of
its own (a `REFERENCE` marketplace copy, or one resolved only through the platform's shared
pool). This link says where to look, not that something is there.
34def __init__(self, strategy_id, validation, compiled_at=attr_dict['compiled_at'].default, required_sources=attr_dict['required_sources'].default, validated_at=attr_dict['validated_at'].default, detail=attr_dict['detail'].default, notices=attr_dict['notices'].default, notices_truncated=attr_dict['notices_truncated'].default, dry_run_incomplete=attr_dict['dry_run_incomplete'].default, validation_stalled=attr_dict['validation_stalled'].default, field_links=attr_dict['field_links'].default): 35 self.strategy_id = strategy_id 36 self.validation = validation 37 self.compiled_at = compiled_at 38 self.required_sources = required_sources 39 self.validated_at = validated_at 40 self.detail = detail 41 self.notices = notices 42 self.notices_truncated = notices_truncated 43 self.dry_run_incomplete = dry_run_incomplete 44 self.validation_stalled = validation_stalled 45 self.field_links = field_links 46 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class StrategyState.
100 def to_dict(self) -> dict[str, Any]: 101 strategy_id = self.strategy_id 102 103 validation = self.validation.value 104 105 compiled_at: str | Unset = UNSET 106 if not isinstance(self.compiled_at, Unset): 107 compiled_at = self.compiled_at.isoformat() 108 109 required_sources: list[str] | Unset = UNSET 110 if not isinstance(self.required_sources, Unset): 111 required_sources = [] 112 for required_sources_item_data in self.required_sources: 113 required_sources_item = required_sources_item_data.value 114 required_sources.append(required_sources_item) 115 116 validated_at: str | Unset = UNSET 117 if not isinstance(self.validated_at, Unset): 118 validated_at = self.validated_at.isoformat() 119 120 detail = self.detail 121 122 notices: list[dict[str, Any]] | Unset = UNSET 123 if not isinstance(self.notices, Unset): 124 notices = [] 125 for notices_item_data in self.notices: 126 notices_item = notices_item_data.to_dict() 127 notices.append(notices_item) 128 129 notices_truncated = self.notices_truncated 130 131 dry_run_incomplete = self.dry_run_incomplete 132 133 validation_stalled = self.validation_stalled 134 135 field_links: dict[str, Any] | Unset = UNSET 136 if not isinstance(self.field_links, Unset): 137 field_links = self.field_links.to_dict() 138 139 field_dict: dict[str, Any] = {} 140 field_dict.update(self.additional_properties) 141 field_dict.update( 142 { 143 "strategyId": strategy_id, 144 "validation": validation, 145 } 146 ) 147 if compiled_at is not UNSET: 148 field_dict["compiledAt"] = compiled_at 149 if required_sources is not UNSET: 150 field_dict["requiredSources"] = required_sources 151 if validated_at is not UNSET: 152 field_dict["validatedAt"] = validated_at 153 if detail is not UNSET: 154 field_dict["detail"] = detail 155 if notices is not UNSET: 156 field_dict["notices"] = notices 157 if notices_truncated is not UNSET: 158 field_dict["noticesTruncated"] = notices_truncated 159 if dry_run_incomplete is not UNSET: 160 field_dict["dryRunIncomplete"] = dry_run_incomplete 161 if validation_stalled is not UNSET: 162 field_dict["validationStalled"] = validation_stalled 163 if field_links is not UNSET: 164 field_dict["_links"] = field_links 165 166 return field_dict
168 @classmethod 169 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 170 from ..models.notice import Notice 171 from ..models.strategy_links import StrategyLinks 172 173 d = dict(src_dict) 174 strategy_id = d.pop("strategyId") 175 176 validation = StrategyStateValidation(d.pop("validation")) 177 178 _compiled_at = d.pop("compiledAt", UNSET) 179 compiled_at: datetime.datetime | Unset 180 if isinstance(_compiled_at, Unset): 181 compiled_at = UNSET 182 else: 183 compiled_at = isoparse(_compiled_at) 184 185 _required_sources = d.pop("requiredSources", UNSET) 186 required_sources: list[StrategyStateRequiredSourcesItem] | Unset = UNSET 187 if _required_sources is not UNSET: 188 required_sources = [] 189 for required_sources_item_data in _required_sources: 190 required_sources_item = StrategyStateRequiredSourcesItem(required_sources_item_data) 191 192 required_sources.append(required_sources_item) 193 194 _validated_at = d.pop("validatedAt", UNSET) 195 validated_at: datetime.datetime | Unset 196 if isinstance(_validated_at, Unset): 197 validated_at = UNSET 198 else: 199 validated_at = isoparse(_validated_at) 200 201 detail = d.pop("detail", UNSET) 202 203 _notices = d.pop("notices", UNSET) 204 notices: list[Notice] | Unset = UNSET 205 if _notices is not UNSET: 206 notices = [] 207 for notices_item_data in _notices: 208 notices_item = Notice.from_dict(notices_item_data) 209 210 notices.append(notices_item) 211 212 notices_truncated = d.pop("noticesTruncated", UNSET) 213 214 dry_run_incomplete = d.pop("dryRunIncomplete", UNSET) 215 216 validation_stalled = d.pop("validationStalled", UNSET) 217 218 _field_links = d.pop("_links", UNSET) 219 field_links: StrategyLinks | Unset 220 if isinstance(_field_links, Unset): 221 field_links = UNSET 222 else: 223 field_links = StrategyLinks.from_dict(_field_links) 224 225 strategy_state = cls( 226 strategy_id=strategy_id, 227 validation=validation, 228 compiled_at=compiled_at, 229 required_sources=required_sources, 230 validated_at=validated_at, 231 detail=detail, 232 notices=notices, 233 notices_truncated=notices_truncated, 234 dry_run_incomplete=dry_run_incomplete, 235 validation_stalled=validation_stalled, 236 field_links=field_links, 237 ) 238 239 strategy_state.additional_properties = d 240 return strategy_state
5class StrategyStateRequiredSourcesItem(str, Enum): 6 FUNDINGRATE = "FundingRate" 7 KLINE = "KLine" 8 TICKER = "Ticker" 9 10 def __str__(self) -> str: 11 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class StrategyStateValidation(str, Enum): 6 FAILED = "failed" 7 NOT_VALIDATED = "not_validated" 8 PASSED = "passed" 9 PENDING = "pending" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
17@_attrs_define 18class StrategySummary: 19 """One entry from `GET /strategies` — the same provenance a full `StrategyState` carries 20 (`compiledAt`, `requiredSources`), without its validation state, so listing stays cheap 21 regardless of how many strategies you have registered. Check a specific strategy's 22 validation with `GET /strategy/{strategyId}`. 23 24 Attributes: 25 strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code 26 always yields the same id, for every caller, whatever its formatting. See 27 `POST /strategy` for exactly which rewrites preserve it and which do not. 28 Example: 6bsh31ikwkuivhtgcoa6s4. 29 compiled_at (datetime.datetime | Unset): When the live compilation was produced. 30 required_sources (list[str] | Unset): The market data this strategy needs. Absent, not empty, when it could 31 not be established without constructing the strategy. 32 """ 33 34 strategy_id: str 35 compiled_at: datetime.datetime | Unset = UNSET 36 required_sources: list[str] | Unset = UNSET 37 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 38 39 def to_dict(self) -> dict[str, Any]: 40 strategy_id = self.strategy_id 41 42 compiled_at: str | Unset = UNSET 43 if not isinstance(self.compiled_at, Unset): 44 compiled_at = self.compiled_at.isoformat() 45 46 required_sources: list[str] | Unset = UNSET 47 if not isinstance(self.required_sources, Unset): 48 required_sources = self.required_sources 49 50 field_dict: dict[str, Any] = {} 51 field_dict.update(self.additional_properties) 52 field_dict.update( 53 { 54 "strategyId": strategy_id, 55 } 56 ) 57 if compiled_at is not UNSET: 58 field_dict["compiledAt"] = compiled_at 59 if required_sources is not UNSET: 60 field_dict["requiredSources"] = required_sources 61 62 return field_dict 63 64 @classmethod 65 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 66 d = dict(src_dict) 67 strategy_id = d.pop("strategyId") 68 69 _compiled_at = d.pop("compiledAt", UNSET) 70 compiled_at: datetime.datetime | Unset 71 if isinstance(_compiled_at, Unset): 72 compiled_at = UNSET 73 else: 74 compiled_at = isoparse(_compiled_at) 75 76 required_sources = cast(list[str], d.pop("requiredSources", UNSET)) 77 78 strategy_summary = cls( 79 strategy_id=strategy_id, 80 compiled_at=compiled_at, 81 required_sources=required_sources, 82 ) 83 84 strategy_summary.additional_properties = d 85 return strategy_summary 86 87 @property 88 def additional_keys(self) -> list[str]: 89 return list(self.additional_properties.keys()) 90 91 def __getitem__(self, key: str) -> Any: 92 return self.additional_properties[key] 93 94 def __setitem__(self, key: str, value: Any) -> None: 95 self.additional_properties[key] = value 96 97 def __delitem__(self, key: str) -> None: 98 del self.additional_properties[key] 99 100 def __contains__(self, key: str) -> bool: 101 return key in self.additional_properties
One entry from GET /strategies — the same provenance a full StrategyState carries
(compiledAt, requiredSources), without its validation state, so listing stays cheap
regardless of how many strategies you have registered. Check a specific strategy's
validation with GET /strategy/{strategyId}.
Attributes:
strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
always yields the same id, for every caller, whatever its formatting. See
`POST /strategy` for exactly which rewrites preserve it and which do not.
Example: 6bsh31ikwkuivhtgcoa6s4.
compiled_at (datetime.datetime | Unset): When the live compilation was produced.
required_sources (list[str] | Unset): The market data this strategy needs. Absent, not empty, when it could
not be established without constructing the strategy.
26def __init__(self, strategy_id, compiled_at=attr_dict['compiled_at'].default, required_sources=attr_dict['required_sources'].default): 27 self.strategy_id = strategy_id 28 self.compiled_at = compiled_at 29 self.required_sources = required_sources 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class StrategySummary.
39 def to_dict(self) -> dict[str, Any]: 40 strategy_id = self.strategy_id 41 42 compiled_at: str | Unset = UNSET 43 if not isinstance(self.compiled_at, Unset): 44 compiled_at = self.compiled_at.isoformat() 45 46 required_sources: list[str] | Unset = UNSET 47 if not isinstance(self.required_sources, Unset): 48 required_sources = self.required_sources 49 50 field_dict: dict[str, Any] = {} 51 field_dict.update(self.additional_properties) 52 field_dict.update( 53 { 54 "strategyId": strategy_id, 55 } 56 ) 57 if compiled_at is not UNSET: 58 field_dict["compiledAt"] = compiled_at 59 if required_sources is not UNSET: 60 field_dict["requiredSources"] = required_sources 61 62 return field_dict
64 @classmethod 65 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 66 d = dict(src_dict) 67 strategy_id = d.pop("strategyId") 68 69 _compiled_at = d.pop("compiledAt", UNSET) 70 compiled_at: datetime.datetime | Unset 71 if isinstance(_compiled_at, Unset): 72 compiled_at = UNSET 73 else: 74 compiled_at = isoparse(_compiled_at) 75 76 required_sources = cast(list[str], d.pop("requiredSources", UNSET)) 77 78 strategy_summary = cls( 79 strategy_id=strategy_id, 80 compiled_at=compiled_at, 81 required_sources=required_sources, 82 ) 83 84 strategy_summary.additional_properties = d 85 return strategy_summary
12@_attrs_define 13class SweepAxisType0: 14 """ 15 Attributes: 16 from_ (float): 17 to (float): 18 step (float): 19 """ 20 21 from_: float 22 to: float 23 step: float 24 25 def to_dict(self) -> dict[str, Any]: 26 from_ = self.from_ 27 28 to = self.to 29 30 step = self.step 31 32 field_dict: dict[str, Any] = {} 33 34 field_dict.update( 35 { 36 "from": from_, 37 "to": to, 38 "step": step, 39 } 40 ) 41 42 return field_dict 43 44 @classmethod 45 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 46 d = dict(src_dict) 47 from_ = d.pop("from") 48 49 to = d.pop("to") 50 51 step = d.pop("step") 52 53 sweep_axis_type_0 = cls( 54 from_=from_, 55 to=to, 56 step=step, 57 ) 58 59 return sweep_axis_type_0
Attributes: from_ (float): to (float): step (float):
Method generated by attrs for class SweepAxisType0.
12@_attrs_define 13class SweepAxisType1: 14 """ 15 Attributes: 16 values (list[bool | float]): 17 """ 18 19 values: list[bool | float] 20 21 def to_dict(self) -> dict[str, Any]: 22 values = [] 23 for values_item_data in self.values: 24 values_item: bool | float 25 values_item = values_item_data 26 values.append(values_item) 27 28 field_dict: dict[str, Any] = {} 29 30 field_dict.update( 31 { 32 "values": values, 33 } 34 ) 35 36 return field_dict 37 38 @classmethod 39 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 40 d = dict(src_dict) 41 values = [] 42 _values = d.pop("values") 43 for values_item_data in _values: 44 45 def _parse_values_item(data: object) -> bool | float: 46 return cast(bool | float, data) 47 48 values_item = _parse_values_item(values_item_data) 49 50 values.append(values_item) 51 52 sweep_axis_type_1 = cls( 53 values=values, 54 ) 55 56 return sweep_axis_type_1
Attributes: values (list[bool | float]):
21 def to_dict(self) -> dict[str, Any]: 22 values = [] 23 for values_item_data in self.values: 24 values_item: bool | float 25 values_item = values_item_data 26 values.append(values_item) 27 28 field_dict: dict[str, Any] = {} 29 30 field_dict.update( 31 { 32 "values": values, 33 } 34 ) 35 36 return field_dict
38 @classmethod 39 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 40 d = dict(src_dict) 41 values = [] 42 _values = d.pop("values") 43 for values_item_data in _values: 44 45 def _parse_values_item(data: object) -> bool | float: 46 return cast(bool | float, data) 47 48 values_item = _parse_values_item(values_item_data) 49 50 values.append(values_item) 51 52 sweep_axis_type_1 = cls( 53 values=values, 54 ) 55 56 return sweep_axis_type_1
16@_attrs_define 17class SweepBaseConfig: 18 """ 19 Attributes: 20 initial_funding (float | Unset): Default: 10000.0. 21 fee_rate (float | Unset): Default: 0.001. 22 buy_fee_rate (float | Unset): 23 sell_fee_rate (float | Unset): 24 fee_leg (SweepBaseConfigFeeLeg | Unset): Default: SweepBaseConfigFeeLeg.RECEIVED. 25 percent_amount_to_lock (float | Unset): 26 """ 27 28 initial_funding: float | Unset = 10000.0 29 fee_rate: float | Unset = 0.001 30 buy_fee_rate: float | Unset = UNSET 31 sell_fee_rate: float | Unset = UNSET 32 fee_leg: SweepBaseConfigFeeLeg | Unset = SweepBaseConfigFeeLeg.RECEIVED 33 percent_amount_to_lock: float | Unset = UNSET 34 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 35 36 def to_dict(self) -> dict[str, Any]: 37 initial_funding = self.initial_funding 38 39 fee_rate = self.fee_rate 40 41 buy_fee_rate = self.buy_fee_rate 42 43 sell_fee_rate = self.sell_fee_rate 44 45 fee_leg: str | Unset = UNSET 46 if not isinstance(self.fee_leg, Unset): 47 fee_leg = self.fee_leg.value 48 49 percent_amount_to_lock = self.percent_amount_to_lock 50 51 field_dict: dict[str, Any] = {} 52 field_dict.update(self.additional_properties) 53 field_dict.update({}) 54 if initial_funding is not UNSET: 55 field_dict["initialFunding"] = initial_funding 56 if fee_rate is not UNSET: 57 field_dict["feeRate"] = fee_rate 58 if buy_fee_rate is not UNSET: 59 field_dict["buyFeeRate"] = buy_fee_rate 60 if sell_fee_rate is not UNSET: 61 field_dict["sellFeeRate"] = sell_fee_rate 62 if fee_leg is not UNSET: 63 field_dict["feeLeg"] = fee_leg 64 if percent_amount_to_lock is not UNSET: 65 field_dict["percentAmountToLock"] = percent_amount_to_lock 66 67 return field_dict 68 69 @classmethod 70 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 71 d = dict(src_dict) 72 initial_funding = d.pop("initialFunding", UNSET) 73 74 fee_rate = d.pop("feeRate", UNSET) 75 76 buy_fee_rate = d.pop("buyFeeRate", UNSET) 77 78 sell_fee_rate = d.pop("sellFeeRate", UNSET) 79 80 _fee_leg = d.pop("feeLeg", UNSET) 81 fee_leg: SweepBaseConfigFeeLeg | Unset 82 if isinstance(_fee_leg, Unset): 83 fee_leg = UNSET 84 else: 85 fee_leg = SweepBaseConfigFeeLeg(_fee_leg) 86 87 percent_amount_to_lock = d.pop("percentAmountToLock", UNSET) 88 89 sweep_base_config = cls( 90 initial_funding=initial_funding, 91 fee_rate=fee_rate, 92 buy_fee_rate=buy_fee_rate, 93 sell_fee_rate=sell_fee_rate, 94 fee_leg=fee_leg, 95 percent_amount_to_lock=percent_amount_to_lock, 96 ) 97 98 sweep_base_config.additional_properties = d 99 return sweep_base_config 100 101 @property 102 def additional_keys(self) -> list[str]: 103 return list(self.additional_properties.keys()) 104 105 def __getitem__(self, key: str) -> Any: 106 return self.additional_properties[key] 107 108 def __setitem__(self, key: str, value: Any) -> None: 109 self.additional_properties[key] = value 110 111 def __delitem__(self, key: str) -> None: 112 del self.additional_properties[key] 113 114 def __contains__(self, key: str) -> bool: 115 return key in self.additional_properties
Attributes: initial_funding (float | Unset): Default: 10000.0. fee_rate (float | Unset): Default: 0.001. buy_fee_rate (float | Unset): sell_fee_rate (float | Unset): fee_leg (SweepBaseConfigFeeLeg | Unset): Default: SweepBaseConfigFeeLeg.RECEIVED. percent_amount_to_lock (float | Unset):
29def __init__(self, initial_funding=attr_dict['initial_funding'].default, fee_rate=attr_dict['fee_rate'].default, buy_fee_rate=attr_dict['buy_fee_rate'].default, sell_fee_rate=attr_dict['sell_fee_rate'].default, fee_leg=attr_dict['fee_leg'].default, percent_amount_to_lock=attr_dict['percent_amount_to_lock'].default): 30 self.initial_funding = initial_funding 31 self.fee_rate = fee_rate 32 self.buy_fee_rate = buy_fee_rate 33 self.sell_fee_rate = sell_fee_rate 34 self.fee_leg = fee_leg 35 self.percent_amount_to_lock = percent_amount_to_lock 36 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepBaseConfig.
36 def to_dict(self) -> dict[str, Any]: 37 initial_funding = self.initial_funding 38 39 fee_rate = self.fee_rate 40 41 buy_fee_rate = self.buy_fee_rate 42 43 sell_fee_rate = self.sell_fee_rate 44 45 fee_leg: str | Unset = UNSET 46 if not isinstance(self.fee_leg, Unset): 47 fee_leg = self.fee_leg.value 48 49 percent_amount_to_lock = self.percent_amount_to_lock 50 51 field_dict: dict[str, Any] = {} 52 field_dict.update(self.additional_properties) 53 field_dict.update({}) 54 if initial_funding is not UNSET: 55 field_dict["initialFunding"] = initial_funding 56 if fee_rate is not UNSET: 57 field_dict["feeRate"] = fee_rate 58 if buy_fee_rate is not UNSET: 59 field_dict["buyFeeRate"] = buy_fee_rate 60 if sell_fee_rate is not UNSET: 61 field_dict["sellFeeRate"] = sell_fee_rate 62 if fee_leg is not UNSET: 63 field_dict["feeLeg"] = fee_leg 64 if percent_amount_to_lock is not UNSET: 65 field_dict["percentAmountToLock"] = percent_amount_to_lock 66 67 return field_dict
69 @classmethod 70 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 71 d = dict(src_dict) 72 initial_funding = d.pop("initialFunding", UNSET) 73 74 fee_rate = d.pop("feeRate", UNSET) 75 76 buy_fee_rate = d.pop("buyFeeRate", UNSET) 77 78 sell_fee_rate = d.pop("sellFeeRate", UNSET) 79 80 _fee_leg = d.pop("feeLeg", UNSET) 81 fee_leg: SweepBaseConfigFeeLeg | Unset 82 if isinstance(_fee_leg, Unset): 83 fee_leg = UNSET 84 else: 85 fee_leg = SweepBaseConfigFeeLeg(_fee_leg) 86 87 percent_amount_to_lock = d.pop("percentAmountToLock", UNSET) 88 89 sweep_base_config = cls( 90 initial_funding=initial_funding, 91 fee_rate=fee_rate, 92 buy_fee_rate=buy_fee_rate, 93 sell_fee_rate=sell_fee_rate, 94 fee_leg=fee_leg, 95 percent_amount_to_lock=percent_amount_to_lock, 96 ) 97 98 sweep_base_config.additional_properties = d 99 return sweep_base_config
5class SweepBaseConfigFeeLeg(str, Enum): 6 BASE = "BASE" 7 QUOTE = "QUOTE" 8 RECEIVED = "RECEIVED" 9 10 def __str__(self) -> str: 11 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
19@_attrs_define 20class SweepHeatmap: 21 """The surface for one pair of axes, with all others collapsed away. 22 23 Attributes: 24 param_a (str | Unset): 25 param_b (str | Unset): 26 cells (list[SweepHeatmapCell] | Unset): 27 """ 28 29 param_a: str | Unset = UNSET 30 param_b: str | Unset = UNSET 31 cells: list[SweepHeatmapCell] | Unset = UNSET 32 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 33 34 def to_dict(self) -> dict[str, Any]: 35 param_a = self.param_a 36 37 param_b = self.param_b 38 39 cells: list[dict[str, Any]] | Unset = UNSET 40 if not isinstance(self.cells, Unset): 41 cells = [] 42 for cells_item_data in self.cells: 43 cells_item = cells_item_data.to_dict() 44 cells.append(cells_item) 45 46 field_dict: dict[str, Any] = {} 47 field_dict.update(self.additional_properties) 48 field_dict.update({}) 49 if param_a is not UNSET: 50 field_dict["paramA"] = param_a 51 if param_b is not UNSET: 52 field_dict["paramB"] = param_b 53 if cells is not UNSET: 54 field_dict["cells"] = cells 55 56 return field_dict 57 58 @classmethod 59 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 60 from ..models.sweep_heatmap_cell import SweepHeatmapCell 61 62 d = dict(src_dict) 63 param_a = d.pop("paramA", UNSET) 64 65 param_b = d.pop("paramB", UNSET) 66 67 _cells = d.pop("cells", UNSET) 68 cells: list[SweepHeatmapCell] | Unset = UNSET 69 if _cells is not UNSET: 70 cells = [] 71 for cells_item_data in _cells: 72 cells_item = SweepHeatmapCell.from_dict(cells_item_data) 73 74 cells.append(cells_item) 75 76 sweep_heatmap = cls( 77 param_a=param_a, 78 param_b=param_b, 79 cells=cells, 80 ) 81 82 sweep_heatmap.additional_properties = d 83 return sweep_heatmap 84 85 @property 86 def additional_keys(self) -> list[str]: 87 return list(self.additional_properties.keys()) 88 89 def __getitem__(self, key: str) -> Any: 90 return self.additional_properties[key] 91 92 def __setitem__(self, key: str, value: Any) -> None: 93 self.additional_properties[key] = value 94 95 def __delitem__(self, key: str) -> None: 96 del self.additional_properties[key] 97 98 def __contains__(self, key: str) -> bool: 99 return key in self.additional_properties
The surface for one pair of axes, with all others collapsed away.
Attributes: param_a (str | Unset): param_b (str | Unset): cells (list[SweepHeatmapCell] | Unset):
26def __init__(self, param_a=attr_dict['param_a'].default, param_b=attr_dict['param_b'].default, cells=attr_dict['cells'].default): 27 self.param_a = param_a 28 self.param_b = param_b 29 self.cells = cells 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepHeatmap.
34 def to_dict(self) -> dict[str, Any]: 35 param_a = self.param_a 36 37 param_b = self.param_b 38 39 cells: list[dict[str, Any]] | Unset = UNSET 40 if not isinstance(self.cells, Unset): 41 cells = [] 42 for cells_item_data in self.cells: 43 cells_item = cells_item_data.to_dict() 44 cells.append(cells_item) 45 46 field_dict: dict[str, Any] = {} 47 field_dict.update(self.additional_properties) 48 field_dict.update({}) 49 if param_a is not UNSET: 50 field_dict["paramA"] = param_a 51 if param_b is not UNSET: 52 field_dict["paramB"] = param_b 53 if cells is not UNSET: 54 field_dict["cells"] = cells 55 56 return field_dict
58 @classmethod 59 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 60 from ..models.sweep_heatmap_cell import SweepHeatmapCell 61 62 d = dict(src_dict) 63 param_a = d.pop("paramA", UNSET) 64 65 param_b = d.pop("paramB", UNSET) 66 67 _cells = d.pop("cells", UNSET) 68 cells: list[SweepHeatmapCell] | Unset = UNSET 69 if _cells is not UNSET: 70 cells = [] 71 for cells_item_data in _cells: 72 cells_item = SweepHeatmapCell.from_dict(cells_item_data) 73 74 cells.append(cells_item) 75 76 sweep_heatmap = cls( 77 param_a=param_a, 78 param_b=param_b, 79 cells=cells, 80 ) 81 82 sweep_heatmap.additional_properties = d 83 return sweep_heatmap
15@_attrs_define 16class SweepHeatmapCell: 17 """ 18 Attributes: 19 value_a (Any | Unset): 20 value_b (Any | Unset): 21 count (int | Unset): 22 best (float | Unset): 23 mean (float | Unset): 24 """ 25 26 value_a: Any | Unset = UNSET 27 value_b: Any | Unset = UNSET 28 count: int | Unset = UNSET 29 best: float | Unset = UNSET 30 mean: float | Unset = UNSET 31 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 32 33 def to_dict(self) -> dict[str, Any]: 34 value_a = self.value_a 35 36 value_b = self.value_b 37 38 count = self.count 39 40 best = self.best 41 42 mean = self.mean 43 44 field_dict: dict[str, Any] = {} 45 field_dict.update(self.additional_properties) 46 field_dict.update({}) 47 if value_a is not UNSET: 48 field_dict["valueA"] = value_a 49 if value_b is not UNSET: 50 field_dict["valueB"] = value_b 51 if count is not UNSET: 52 field_dict["count"] = count 53 if best is not UNSET: 54 field_dict["best"] = best 55 if mean is not UNSET: 56 field_dict["mean"] = mean 57 58 return field_dict 59 60 @classmethod 61 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 62 d = dict(src_dict) 63 value_a = d.pop("valueA", UNSET) 64 65 value_b = d.pop("valueB", UNSET) 66 67 count = d.pop("count", UNSET) 68 69 best = d.pop("best", UNSET) 70 71 mean = d.pop("mean", UNSET) 72 73 sweep_heatmap_cell = cls( 74 value_a=value_a, 75 value_b=value_b, 76 count=count, 77 best=best, 78 mean=mean, 79 ) 80 81 sweep_heatmap_cell.additional_properties = d 82 return sweep_heatmap_cell 83 84 @property 85 def additional_keys(self) -> list[str]: 86 return list(self.additional_properties.keys()) 87 88 def __getitem__(self, key: str) -> Any: 89 return self.additional_properties[key] 90 91 def __setitem__(self, key: str, value: Any) -> None: 92 self.additional_properties[key] = value 93 94 def __delitem__(self, key: str) -> None: 95 del self.additional_properties[key] 96 97 def __contains__(self, key: str) -> bool: 98 return key in self.additional_properties
Attributes: value_a (Any | Unset): value_b (Any | Unset): count (int | Unset): best (float | Unset): mean (float | Unset):
28def __init__(self, value_a=attr_dict['value_a'].default, value_b=attr_dict['value_b'].default, count=attr_dict['count'].default, best=attr_dict['best'].default, mean=attr_dict['mean'].default): 29 self.value_a = value_a 30 self.value_b = value_b 31 self.count = count 32 self.best = best 33 self.mean = mean 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepHeatmapCell.
33 def to_dict(self) -> dict[str, Any]: 34 value_a = self.value_a 35 36 value_b = self.value_b 37 38 count = self.count 39 40 best = self.best 41 42 mean = self.mean 43 44 field_dict: dict[str, Any] = {} 45 field_dict.update(self.additional_properties) 46 field_dict.update({}) 47 if value_a is not UNSET: 48 field_dict["valueA"] = value_a 49 if value_b is not UNSET: 50 field_dict["valueB"] = value_b 51 if count is not UNSET: 52 field_dict["count"] = count 53 if best is not UNSET: 54 field_dict["best"] = best 55 if mean is not UNSET: 56 field_dict["mean"] = mean 57 58 return field_dict
60 @classmethod 61 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 62 d = dict(src_dict) 63 value_a = d.pop("valueA", UNSET) 64 65 value_b = d.pop("valueB", UNSET) 66 67 count = d.pop("count", UNSET) 68 69 best = d.pop("best", UNSET) 70 71 mean = d.pop("mean", UNSET) 72 73 sweep_heatmap_cell = cls( 74 value_a=value_a, 75 value_b=value_b, 76 count=count, 77 best=best, 78 mean=mean, 79 ) 80 81 sweep_heatmap_cell.additional_properties = d 82 return sweep_heatmap_cell
19@_attrs_define 20class SweepMarginal: 21 """One axis, with every other axis collapsed away. 22 23 Attributes: 24 param (str | Unset): 25 points (list[SweepMarginalPoint] | Unset): 26 """ 27 28 param: str | Unset = UNSET 29 points: list[SweepMarginalPoint] | Unset = UNSET 30 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 31 32 def to_dict(self) -> dict[str, Any]: 33 param = self.param 34 35 points: list[dict[str, Any]] | Unset = UNSET 36 if not isinstance(self.points, Unset): 37 points = [] 38 for points_item_data in self.points: 39 points_item = points_item_data.to_dict() 40 points.append(points_item) 41 42 field_dict: dict[str, Any] = {} 43 field_dict.update(self.additional_properties) 44 field_dict.update({}) 45 if param is not UNSET: 46 field_dict["param"] = param 47 if points is not UNSET: 48 field_dict["points"] = points 49 50 return field_dict 51 52 @classmethod 53 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 54 from ..models.sweep_marginal_point import SweepMarginalPoint 55 56 d = dict(src_dict) 57 param = d.pop("param", UNSET) 58 59 _points = d.pop("points", UNSET) 60 points: list[SweepMarginalPoint] | Unset = UNSET 61 if _points is not UNSET: 62 points = [] 63 for points_item_data in _points: 64 points_item = SweepMarginalPoint.from_dict(points_item_data) 65 66 points.append(points_item) 67 68 sweep_marginal = cls( 69 param=param, 70 points=points, 71 ) 72 73 sweep_marginal.additional_properties = d 74 return sweep_marginal 75 76 @property 77 def additional_keys(self) -> list[str]: 78 return list(self.additional_properties.keys()) 79 80 def __getitem__(self, key: str) -> Any: 81 return self.additional_properties[key] 82 83 def __setitem__(self, key: str, value: Any) -> None: 84 self.additional_properties[key] = value 85 86 def __delitem__(self, key: str) -> None: 87 del self.additional_properties[key] 88 89 def __contains__(self, key: str) -> bool: 90 return key in self.additional_properties
One axis, with every other axis collapsed away.
Attributes: param (str | Unset): points (list[SweepMarginalPoint] | Unset):
25def __init__(self, param=attr_dict['param'].default, points=attr_dict['points'].default): 26 self.param = param 27 self.points = points 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepMarginal.
32 def to_dict(self) -> dict[str, Any]: 33 param = self.param 34 35 points: list[dict[str, Any]] | Unset = UNSET 36 if not isinstance(self.points, Unset): 37 points = [] 38 for points_item_data in self.points: 39 points_item = points_item_data.to_dict() 40 points.append(points_item) 41 42 field_dict: dict[str, Any] = {} 43 field_dict.update(self.additional_properties) 44 field_dict.update({}) 45 if param is not UNSET: 46 field_dict["param"] = param 47 if points is not UNSET: 48 field_dict["points"] = points 49 50 return field_dict
52 @classmethod 53 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 54 from ..models.sweep_marginal_point import SweepMarginalPoint 55 56 d = dict(src_dict) 57 param = d.pop("param", UNSET) 58 59 _points = d.pop("points", UNSET) 60 points: list[SweepMarginalPoint] | Unset = UNSET 61 if _points is not UNSET: 62 points = [] 63 for points_item_data in _points: 64 points_item = SweepMarginalPoint.from_dict(points_item_data) 65 66 points.append(points_item) 67 68 sweep_marginal = cls( 69 param=param, 70 points=points, 71 ) 72 73 sweep_marginal.additional_properties = d 74 return sweep_marginal
15@_attrs_define 16class SweepMarginalPoint: 17 """How the objective behaved at one value of one axis. `best` and `mean` disagreeing is informative rather than noise: 18 a high `best` with a poor `mean` marks a value that only works alongside particular settings of the other axes. 19 20 Attributes: 21 value (Any | Unset): The axis value, as it appears in a run's parameters. 22 count (int | Unset): Non-aborted runs that used this value. 23 best (float | Unset): 24 mean (float | Unset): 25 worst (float | Unset): 26 """ 27 28 value: Any | Unset = UNSET 29 count: int | Unset = UNSET 30 best: float | Unset = UNSET 31 mean: float | Unset = UNSET 32 worst: float | Unset = UNSET 33 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 34 35 def to_dict(self) -> dict[str, Any]: 36 value = self.value 37 38 count = self.count 39 40 best = self.best 41 42 mean = self.mean 43 44 worst = self.worst 45 46 field_dict: dict[str, Any] = {} 47 field_dict.update(self.additional_properties) 48 field_dict.update({}) 49 if value is not UNSET: 50 field_dict["value"] = value 51 if count is not UNSET: 52 field_dict["count"] = count 53 if best is not UNSET: 54 field_dict["best"] = best 55 if mean is not UNSET: 56 field_dict["mean"] = mean 57 if worst is not UNSET: 58 field_dict["worst"] = worst 59 60 return field_dict 61 62 @classmethod 63 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 64 d = dict(src_dict) 65 value = d.pop("value", UNSET) 66 67 count = d.pop("count", UNSET) 68 69 best = d.pop("best", UNSET) 70 71 mean = d.pop("mean", UNSET) 72 73 worst = d.pop("worst", UNSET) 74 75 sweep_marginal_point = cls( 76 value=value, 77 count=count, 78 best=best, 79 mean=mean, 80 worst=worst, 81 ) 82 83 sweep_marginal_point.additional_properties = d 84 return sweep_marginal_point 85 86 @property 87 def additional_keys(self) -> list[str]: 88 return list(self.additional_properties.keys()) 89 90 def __getitem__(self, key: str) -> Any: 91 return self.additional_properties[key] 92 93 def __setitem__(self, key: str, value: Any) -> None: 94 self.additional_properties[key] = value 95 96 def __delitem__(self, key: str) -> None: 97 del self.additional_properties[key] 98 99 def __contains__(self, key: str) -> bool: 100 return key in self.additional_properties
How the objective behaved at one value of one axis. best and mean disagreeing is informative rather than noise:
a high best with a poor mean marks a value that only works alongside particular settings of the other axes.
Attributes:
value (Any | Unset): The axis value, as it appears in a run's parameters.
count (int | Unset): Non-aborted runs that used this value.
best (float | Unset):
mean (float | Unset):
worst (float | Unset):
28def __init__(self, value=attr_dict['value'].default, count=attr_dict['count'].default, best=attr_dict['best'].default, mean=attr_dict['mean'].default, worst=attr_dict['worst'].default): 29 self.value = value 30 self.count = count 31 self.best = best 32 self.mean = mean 33 self.worst = worst 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepMarginalPoint.
35 def to_dict(self) -> dict[str, Any]: 36 value = self.value 37 38 count = self.count 39 40 best = self.best 41 42 mean = self.mean 43 44 worst = self.worst 45 46 field_dict: dict[str, Any] = {} 47 field_dict.update(self.additional_properties) 48 field_dict.update({}) 49 if value is not UNSET: 50 field_dict["value"] = value 51 if count is not UNSET: 52 field_dict["count"] = count 53 if best is not UNSET: 54 field_dict["best"] = best 55 if mean is not UNSET: 56 field_dict["mean"] = mean 57 if worst is not UNSET: 58 field_dict["worst"] = worst 59 60 return field_dict
62 @classmethod 63 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 64 d = dict(src_dict) 65 value = d.pop("value", UNSET) 66 67 count = d.pop("count", UNSET) 68 69 best = d.pop("best", UNSET) 70 71 mean = d.pop("mean", UNSET) 72 73 worst = d.pop("worst", UNSET) 74 75 sweep_marginal_point = cls( 76 value=value, 77 count=count, 78 best=best, 79 mean=mean, 80 worst=worst, 81 ) 82 83 sweep_marginal_point.additional_properties = d 84 return sweep_marginal_point
15@_attrs_define 16class SweepProgress: 17 """How far along a sweep is, and — when the sweep is still running — enough to tell a healthy one from a stuck one. The 18 counts partition the shards (or, for a walk-forward sweep, the folds): every unit is either finished, failed, 19 waiting to be retried, or not yet started. 20 21 Attributes: 22 done (int): 23 total (int): 24 aborted (int): Individual runs that executed and aborted. A row-level count: a shard that fails before producing 25 any rows leaves this at 0, which is why `failedShards` exists alongside it. 26 shard_count (int): 27 pending_shards (int): 28 failed_shards (int): Shards (or folds) that failed and will not be retried. Distinct from `aborted`: this counts 29 whole units that never reported, not runs that ran badly. 30 retrying (int): Units whose last attempt failed on something transient — an I/O error, a worker that died mid- 31 read — and which are queued to be attempted again. Not counted as failures, because they have not failed yet; a 32 sweep with a non-zero value here is still expected to complete. 33 not_started (int): Units that have not reported anything yet. Covers both work still queued behind other work 34 and work claimed by a worker that stopped before it began, which is why a sweep with a persistent value here and 35 a rising `stalledSeconds` is worth looking at. 36 stalled_seconds (int | Unset): Seconds since anything last advanced. Omitted on a finished sweep, where it would 37 only measure how long ago it finished, and on sweeps submitted before this field existed. 38 eta_seconds (int | Unset): Rough seconds remaining, extrapolated from the rate observed so far and assuming 39 nothing else competes for workers. Runs conservative in practice — it has measured 2–5× long when a sweep spent 40 part of its life waiting to be retried, since that wait dilutes the observed rate. **Omitted, never zero, when 41 it cannot be computed**: a sweep with nothing finished yet has no rate to extrapolate from, and a zero would 42 read as "about to finish". Excludes queue wait entirely; `retrying` and `stalledSeconds` are where that shows 43 up. 44 """ 45 46 done: int 47 total: int 48 aborted: int 49 shard_count: int 50 pending_shards: int 51 failed_shards: int 52 retrying: int 53 not_started: int 54 stalled_seconds: int | Unset = UNSET 55 eta_seconds: int | Unset = UNSET 56 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 57 58 def to_dict(self) -> dict[str, Any]: 59 done = self.done 60 61 total = self.total 62 63 aborted = self.aborted 64 65 shard_count = self.shard_count 66 67 pending_shards = self.pending_shards 68 69 failed_shards = self.failed_shards 70 71 retrying = self.retrying 72 73 not_started = self.not_started 74 75 stalled_seconds = self.stalled_seconds 76 77 eta_seconds = self.eta_seconds 78 79 field_dict: dict[str, Any] = {} 80 field_dict.update(self.additional_properties) 81 field_dict.update( 82 { 83 "done": done, 84 "total": total, 85 "aborted": aborted, 86 "shardCount": shard_count, 87 "pendingShards": pending_shards, 88 "failedShards": failed_shards, 89 "retrying": retrying, 90 "notStarted": not_started, 91 } 92 ) 93 if stalled_seconds is not UNSET: 94 field_dict["stalledSeconds"] = stalled_seconds 95 if eta_seconds is not UNSET: 96 field_dict["etaSeconds"] = eta_seconds 97 98 return field_dict 99 100 @classmethod 101 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 102 d = dict(src_dict) 103 done = d.pop("done") 104 105 total = d.pop("total") 106 107 aborted = d.pop("aborted") 108 109 shard_count = d.pop("shardCount") 110 111 pending_shards = d.pop("pendingShards") 112 113 failed_shards = d.pop("failedShards") 114 115 retrying = d.pop("retrying") 116 117 not_started = d.pop("notStarted") 118 119 stalled_seconds = d.pop("stalledSeconds", UNSET) 120 121 eta_seconds = d.pop("etaSeconds", UNSET) 122 123 sweep_progress = cls( 124 done=done, 125 total=total, 126 aborted=aborted, 127 shard_count=shard_count, 128 pending_shards=pending_shards, 129 failed_shards=failed_shards, 130 retrying=retrying, 131 not_started=not_started, 132 stalled_seconds=stalled_seconds, 133 eta_seconds=eta_seconds, 134 ) 135 136 sweep_progress.additional_properties = d 137 return sweep_progress 138 139 @property 140 def additional_keys(self) -> list[str]: 141 return list(self.additional_properties.keys()) 142 143 def __getitem__(self, key: str) -> Any: 144 return self.additional_properties[key] 145 146 def __setitem__(self, key: str, value: Any) -> None: 147 self.additional_properties[key] = value 148 149 def __delitem__(self, key: str) -> None: 150 del self.additional_properties[key] 151 152 def __contains__(self, key: str) -> bool: 153 return key in self.additional_properties
How far along a sweep is, and — when the sweep is still running — enough to tell a healthy one from a stuck one. The counts partition the shards (or, for a walk-forward sweep, the folds): every unit is either finished, failed, waiting to be retried, or not yet started.
Attributes:
done (int):
total (int):
aborted (int): Individual runs that executed and aborted. A row-level count: a shard that fails before producing
any rows leaves this at 0, which is why `failedShards` exists alongside it.
shard_count (int):
pending_shards (int):
failed_shards (int): Shards (or folds) that failed and will not be retried. Distinct from `aborted`: this counts
whole units that never reported, not runs that ran badly.
retrying (int): Units whose last attempt failed on something transient — an I/O error, a worker that died mid-
read — and which are queued to be attempted again. Not counted as failures, because they have not failed yet; a
sweep with a non-zero value here is still expected to complete.
not_started (int): Units that have not reported anything yet. Covers both work still queued behind other work
and work claimed by a worker that stopped before it began, which is why a sweep with a persistent value here and
a rising `stalledSeconds` is worth looking at.
stalled_seconds (int | Unset): Seconds since anything last advanced. Omitted on a finished sweep, where it would
only measure how long ago it finished, and on sweeps submitted before this field existed.
eta_seconds (int | Unset): Rough seconds remaining, extrapolated from the rate observed so far and assuming
nothing else competes for workers. Runs conservative in practice — it has measured 2–5× long when a sweep spent
part of its life waiting to be retried, since that wait dilutes the observed rate. **Omitted, never zero, when
it cannot be computed**: a sweep with nothing finished yet has no rate to extrapolate from, and a zero would
read as "about to finish". Excludes queue wait entirely; `retrying` and `stalledSeconds` are where that shows
up.
33def __init__(self, done, total, aborted, shard_count, pending_shards, failed_shards, retrying, not_started, stalled_seconds=attr_dict['stalled_seconds'].default, eta_seconds=attr_dict['eta_seconds'].default): 34 self.done = done 35 self.total = total 36 self.aborted = aborted 37 self.shard_count = shard_count 38 self.pending_shards = pending_shards 39 self.failed_shards = failed_shards 40 self.retrying = retrying 41 self.not_started = not_started 42 self.stalled_seconds = stalled_seconds 43 self.eta_seconds = eta_seconds 44 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepProgress.
58 def to_dict(self) -> dict[str, Any]: 59 done = self.done 60 61 total = self.total 62 63 aborted = self.aborted 64 65 shard_count = self.shard_count 66 67 pending_shards = self.pending_shards 68 69 failed_shards = self.failed_shards 70 71 retrying = self.retrying 72 73 not_started = self.not_started 74 75 stalled_seconds = self.stalled_seconds 76 77 eta_seconds = self.eta_seconds 78 79 field_dict: dict[str, Any] = {} 80 field_dict.update(self.additional_properties) 81 field_dict.update( 82 { 83 "done": done, 84 "total": total, 85 "aborted": aborted, 86 "shardCount": shard_count, 87 "pendingShards": pending_shards, 88 "failedShards": failed_shards, 89 "retrying": retrying, 90 "notStarted": not_started, 91 } 92 ) 93 if stalled_seconds is not UNSET: 94 field_dict["stalledSeconds"] = stalled_seconds 95 if eta_seconds is not UNSET: 96 field_dict["etaSeconds"] = eta_seconds 97 98 return field_dict
100 @classmethod 101 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 102 d = dict(src_dict) 103 done = d.pop("done") 104 105 total = d.pop("total") 106 107 aborted = d.pop("aborted") 108 109 shard_count = d.pop("shardCount") 110 111 pending_shards = d.pop("pendingShards") 112 113 failed_shards = d.pop("failedShards") 114 115 retrying = d.pop("retrying") 116 117 not_started = d.pop("notStarted") 118 119 stalled_seconds = d.pop("stalledSeconds", UNSET) 120 121 eta_seconds = d.pop("etaSeconds", UNSET) 122 123 sweep_progress = cls( 124 done=done, 125 total=total, 126 aborted=aborted, 127 shard_count=shard_count, 128 pending_shards=pending_shards, 129 failed_shards=failed_shards, 130 retrying=retrying, 131 not_started=not_started, 132 stalled_seconds=stalled_seconds, 133 eta_seconds=eta_seconds, 134 ) 135 136 sweep_progress.additional_properties = d 137 return sweep_progress
20@_attrs_define 21class SweepRunRow: 22 """ 23 Attributes: 24 run_ix (int): Deterministic zero-based expansion index, stable across shards and ranking. 25 params (SweepRunRowParams): 26 sharpe (float): 27 sortino (float): 28 pnl (float): Absolute net PnL in the output currency. 29 pnl_pct (float): 30 cagr (float): 31 max_dd_pct (float): 32 trades (int): 33 win_rate (float): 34 below_trade_floor (bool): 35 aborted (bool): 36 runtime_ms (int): 37 rank (int | Unset): Present only in the `ranked` view. 38 plateau_score (float | Unset): The objective of the worst run in this point's immediate neighbourhood — how well 39 the region around it holds up, not how well it scored itself. Present only in the `ranked` view when plateau 40 ranking applied. Always read together with `neighbourCount`. 41 neighbour_count (int | Unset): How many neighbouring parameter points backed the `plateauScore`. Zero means the 42 point had no neighbours in the grid, so its score is unevidenced rather than confirmed — the value alone cannot 43 be distinguished from a genuinely robust one. 44 deflated_sharpe (float | Unset): Probability that this run's Sharpe reflects real edge rather than the best draw 45 from however many parameter vectors were tried. Above ~0.95 the result survives the multiple-testing correction; 46 near 0.5 or below it is indistinguishable from the best of a pile of coin flips. Absent on aborted runs, and on 47 sweeps with too few trials to establish any dispersion to deflate against. 48 equity_curve (EquityCurveResult | Unset): An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`, 49 `timestamps` + `equities` (parallel arrays) when `SHORT`. Used identically wherever a curve is returned — a 50 plain backtest's inline `equityCurve` and a sweep row's `equityCurve` are the same type. `url` is present 51 *instead of* any points when the curve is served by pointer rather than inline (a sweep row's top-N winners 52 only): `GET` it separately to fetch this exact same shape with the points populated. 53 """ 54 55 run_ix: int 56 params: SweepRunRowParams 57 sharpe: float 58 sortino: float 59 pnl: float 60 pnl_pct: float 61 cagr: float 62 max_dd_pct: float 63 trades: int 64 win_rate: float 65 below_trade_floor: bool 66 aborted: bool 67 runtime_ms: int 68 rank: int | Unset = UNSET 69 plateau_score: float | Unset = UNSET 70 neighbour_count: int | Unset = UNSET 71 deflated_sharpe: float | Unset = UNSET 72 equity_curve: EquityCurveResult | Unset = UNSET 73 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 74 75 def to_dict(self) -> dict[str, Any]: 76 run_ix = self.run_ix 77 78 params = self.params.to_dict() 79 80 sharpe = self.sharpe 81 82 sortino = self.sortino 83 84 pnl = self.pnl 85 86 pnl_pct = self.pnl_pct 87 88 cagr = self.cagr 89 90 max_dd_pct = self.max_dd_pct 91 92 trades = self.trades 93 94 win_rate = self.win_rate 95 96 below_trade_floor = self.below_trade_floor 97 98 aborted = self.aborted 99 100 runtime_ms = self.runtime_ms 101 102 rank = self.rank 103 104 plateau_score = self.plateau_score 105 106 neighbour_count = self.neighbour_count 107 108 deflated_sharpe = self.deflated_sharpe 109 110 equity_curve: dict[str, Any] | Unset = UNSET 111 if not isinstance(self.equity_curve, Unset): 112 equity_curve = self.equity_curve.to_dict() 113 114 field_dict: dict[str, Any] = {} 115 field_dict.update(self.additional_properties) 116 field_dict.update( 117 { 118 "runIx": run_ix, 119 "params": params, 120 "sharpe": sharpe, 121 "sortino": sortino, 122 "pnl": pnl, 123 "pnlPct": pnl_pct, 124 "cagr": cagr, 125 "maxDdPct": max_dd_pct, 126 "trades": trades, 127 "winRate": win_rate, 128 "belowTradeFloor": below_trade_floor, 129 "aborted": aborted, 130 "runtimeMs": runtime_ms, 131 } 132 ) 133 if rank is not UNSET: 134 field_dict["rank"] = rank 135 if plateau_score is not UNSET: 136 field_dict["plateauScore"] = plateau_score 137 if neighbour_count is not UNSET: 138 field_dict["neighbourCount"] = neighbour_count 139 if deflated_sharpe is not UNSET: 140 field_dict["deflatedSharpe"] = deflated_sharpe 141 if equity_curve is not UNSET: 142 field_dict["equityCurve"] = equity_curve 143 144 return field_dict 145 146 @classmethod 147 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 148 from ..models.equity_curve_result import EquityCurveResult 149 from ..models.sweep_run_row_params import SweepRunRowParams 150 151 d = dict(src_dict) 152 run_ix = d.pop("runIx") 153 154 params = SweepRunRowParams.from_dict(d.pop("params")) 155 156 sharpe = d.pop("sharpe") 157 158 sortino = d.pop("sortino") 159 160 pnl = d.pop("pnl") 161 162 pnl_pct = d.pop("pnlPct") 163 164 cagr = d.pop("cagr") 165 166 max_dd_pct = d.pop("maxDdPct") 167 168 trades = d.pop("trades") 169 170 win_rate = d.pop("winRate") 171 172 below_trade_floor = d.pop("belowTradeFloor") 173 174 aborted = d.pop("aborted") 175 176 runtime_ms = d.pop("runtimeMs") 177 178 rank = d.pop("rank", UNSET) 179 180 plateau_score = d.pop("plateauScore", UNSET) 181 182 neighbour_count = d.pop("neighbourCount", UNSET) 183 184 deflated_sharpe = d.pop("deflatedSharpe", UNSET) 185 186 _equity_curve = d.pop("equityCurve", UNSET) 187 equity_curve: EquityCurveResult | Unset 188 if isinstance(_equity_curve, Unset): 189 equity_curve = UNSET 190 else: 191 equity_curve = EquityCurveResult.from_dict(_equity_curve) 192 193 sweep_run_row = cls( 194 run_ix=run_ix, 195 params=params, 196 sharpe=sharpe, 197 sortino=sortino, 198 pnl=pnl, 199 pnl_pct=pnl_pct, 200 cagr=cagr, 201 max_dd_pct=max_dd_pct, 202 trades=trades, 203 win_rate=win_rate, 204 below_trade_floor=below_trade_floor, 205 aborted=aborted, 206 runtime_ms=runtime_ms, 207 rank=rank, 208 plateau_score=plateau_score, 209 neighbour_count=neighbour_count, 210 deflated_sharpe=deflated_sharpe, 211 equity_curve=equity_curve, 212 ) 213 214 sweep_run_row.additional_properties = d 215 return sweep_run_row 216 217 @property 218 def additional_keys(self) -> list[str]: 219 return list(self.additional_properties.keys()) 220 221 def __getitem__(self, key: str) -> Any: 222 return self.additional_properties[key] 223 224 def __setitem__(self, key: str, value: Any) -> None: 225 self.additional_properties[key] = value 226 227 def __delitem__(self, key: str) -> None: 228 del self.additional_properties[key] 229 230 def __contains__(self, key: str) -> bool: 231 return key in self.additional_properties
Attributes:
run_ix (int): Deterministic zero-based expansion index, stable across shards and ranking.
params (SweepRunRowParams):
sharpe (float):
sortino (float):
pnl (float): Absolute net PnL in the output currency.
pnl_pct (float):
cagr (float):
max_dd_pct (float):
trades (int):
win_rate (float):
below_trade_floor (bool):
aborted (bool):
runtime_ms (int):
rank (int | Unset): Present only in the ranked view.
plateau_score (float | Unset): The objective of the worst run in this point's immediate neighbourhood — how well
the region around it holds up, not how well it scored itself. Present only in the ranked view when plateau
ranking applied. Always read together with neighbourCount.
neighbour_count (int | Unset): How many neighbouring parameter points backed the plateauScore. Zero means the
point had no neighbours in the grid, so its score is unevidenced rather than confirmed — the value alone cannot
be distinguished from a genuinely robust one.
deflated_sharpe (float | Unset): Probability that this run's Sharpe reflects real edge rather than the best draw
from however many parameter vectors were tried. Above ~0.95 the result survives the multiple-testing correction;
near 0.5 or below it is indistinguishable from the best of a pile of coin flips. Absent on aborted runs, and on
sweeps with too few trials to establish any dispersion to deflate against.
equity_curve (EquityCurveResult | Unset): An equity curve, shaped per meta.outMode: points when ARRAY,
timestamps + equities (parallel arrays) when SHORT. Used identically wherever a curve is returned — a
plain backtest's inline equityCurve and a sweep row's equityCurve are the same type. url is present
instead of any points when the curve is served by pointer rather than inline (a sweep row's top-N winners
only): GET it separately to fetch this exact same shape with the points populated.
41def __init__(self, run_ix, params, sharpe, sortino, pnl, pnl_pct, cagr, max_dd_pct, trades, win_rate, below_trade_floor, aborted, runtime_ms, rank=attr_dict['rank'].default, plateau_score=attr_dict['plateau_score'].default, neighbour_count=attr_dict['neighbour_count'].default, deflated_sharpe=attr_dict['deflated_sharpe'].default, equity_curve=attr_dict['equity_curve'].default): 42 self.run_ix = run_ix 43 self.params = params 44 self.sharpe = sharpe 45 self.sortino = sortino 46 self.pnl = pnl 47 self.pnl_pct = pnl_pct 48 self.cagr = cagr 49 self.max_dd_pct = max_dd_pct 50 self.trades = trades 51 self.win_rate = win_rate 52 self.below_trade_floor = below_trade_floor 53 self.aborted = aborted 54 self.runtime_ms = runtime_ms 55 self.rank = rank 56 self.plateau_score = plateau_score 57 self.neighbour_count = neighbour_count 58 self.deflated_sharpe = deflated_sharpe 59 self.equity_curve = equity_curve 60 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepRunRow.
75 def to_dict(self) -> dict[str, Any]: 76 run_ix = self.run_ix 77 78 params = self.params.to_dict() 79 80 sharpe = self.sharpe 81 82 sortino = self.sortino 83 84 pnl = self.pnl 85 86 pnl_pct = self.pnl_pct 87 88 cagr = self.cagr 89 90 max_dd_pct = self.max_dd_pct 91 92 trades = self.trades 93 94 win_rate = self.win_rate 95 96 below_trade_floor = self.below_trade_floor 97 98 aborted = self.aborted 99 100 runtime_ms = self.runtime_ms 101 102 rank = self.rank 103 104 plateau_score = self.plateau_score 105 106 neighbour_count = self.neighbour_count 107 108 deflated_sharpe = self.deflated_sharpe 109 110 equity_curve: dict[str, Any] | Unset = UNSET 111 if not isinstance(self.equity_curve, Unset): 112 equity_curve = self.equity_curve.to_dict() 113 114 field_dict: dict[str, Any] = {} 115 field_dict.update(self.additional_properties) 116 field_dict.update( 117 { 118 "runIx": run_ix, 119 "params": params, 120 "sharpe": sharpe, 121 "sortino": sortino, 122 "pnl": pnl, 123 "pnlPct": pnl_pct, 124 "cagr": cagr, 125 "maxDdPct": max_dd_pct, 126 "trades": trades, 127 "winRate": win_rate, 128 "belowTradeFloor": below_trade_floor, 129 "aborted": aborted, 130 "runtimeMs": runtime_ms, 131 } 132 ) 133 if rank is not UNSET: 134 field_dict["rank"] = rank 135 if plateau_score is not UNSET: 136 field_dict["plateauScore"] = plateau_score 137 if neighbour_count is not UNSET: 138 field_dict["neighbourCount"] = neighbour_count 139 if deflated_sharpe is not UNSET: 140 field_dict["deflatedSharpe"] = deflated_sharpe 141 if equity_curve is not UNSET: 142 field_dict["equityCurve"] = equity_curve 143 144 return field_dict
146 @classmethod 147 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 148 from ..models.equity_curve_result import EquityCurveResult 149 from ..models.sweep_run_row_params import SweepRunRowParams 150 151 d = dict(src_dict) 152 run_ix = d.pop("runIx") 153 154 params = SweepRunRowParams.from_dict(d.pop("params")) 155 156 sharpe = d.pop("sharpe") 157 158 sortino = d.pop("sortino") 159 160 pnl = d.pop("pnl") 161 162 pnl_pct = d.pop("pnlPct") 163 164 cagr = d.pop("cagr") 165 166 max_dd_pct = d.pop("maxDdPct") 167 168 trades = d.pop("trades") 169 170 win_rate = d.pop("winRate") 171 172 below_trade_floor = d.pop("belowTradeFloor") 173 174 aborted = d.pop("aborted") 175 176 runtime_ms = d.pop("runtimeMs") 177 178 rank = d.pop("rank", UNSET) 179 180 plateau_score = d.pop("plateauScore", UNSET) 181 182 neighbour_count = d.pop("neighbourCount", UNSET) 183 184 deflated_sharpe = d.pop("deflatedSharpe", UNSET) 185 186 _equity_curve = d.pop("equityCurve", UNSET) 187 equity_curve: EquityCurveResult | Unset 188 if isinstance(_equity_curve, Unset): 189 equity_curve = UNSET 190 else: 191 equity_curve = EquityCurveResult.from_dict(_equity_curve) 192 193 sweep_run_row = cls( 194 run_ix=run_ix, 195 params=params, 196 sharpe=sharpe, 197 sortino=sortino, 198 pnl=pnl, 199 pnl_pct=pnl_pct, 200 cagr=cagr, 201 max_dd_pct=max_dd_pct, 202 trades=trades, 203 win_rate=win_rate, 204 below_trade_floor=below_trade_floor, 205 aborted=aborted, 206 runtime_ms=runtime_ms, 207 rank=rank, 208 plateau_score=plateau_score, 209 neighbour_count=neighbour_count, 210 deflated_sharpe=deflated_sharpe, 211 equity_curve=equity_curve, 212 ) 213 214 sweep_run_row.additional_properties = d 215 return sweep_run_row
13@_attrs_define 14class SweepRunRowParams: 15 """ """ 16 17 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 18 19 def to_dict(self) -> dict[str, Any]: 20 21 field_dict: dict[str, Any] = {} 22 field_dict.update(self.additional_properties) 23 24 return field_dict 25 26 @classmethod 27 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 28 d = dict(src_dict) 29 sweep_run_row_params = cls() 30 31 sweep_run_row_params.additional_properties = d 32 return sweep_run_row_params 33 34 @property 35 def additional_keys(self) -> list[str]: 36 return list(self.additional_properties.keys()) 37 38 def __getitem__(self, key: str) -> Any: 39 return self.additional_properties[key] 40 41 def __setitem__(self, key: str, value: Any) -> None: 42 self.additional_properties[key] = value 43 44 def __delitem__(self, key: str) -> None: 45 del self.additional_properties[key] 46 47 def __contains__(self, key: str) -> bool: 48 return key in self.additional_properties
22@_attrs_define 23class SweepSensitivity: 24 """Sensitivity aggregates over a sweep's stored rows. Marginals are always complete; heatmaps may be capped, in which 25 case `heatmapsTruncated` is true. 26 27 Attributes: 28 sweep_id (str | Unset): 29 status (SweepSensitivityStatus | Unset): 30 objective (SweepSensitivityObjective | Unset): 31 rows_analysed (int | Unset): Rows available when this was computed. Grows while a sweep is still running. 32 marginals (list[SweepMarginal] | Unset): 33 heatmaps (list[SweepHeatmap] | Unset): 34 heatmaps_truncated (bool | Unset): True when at least one two-parameter surface was left out to stay inside the 35 response budget. Told explicitly because a silently short list would read as "these are all the interactions", 36 which is the wrong thing to conclude from a sensitivity view. 37 """ 38 39 sweep_id: str | Unset = UNSET 40 status: SweepSensitivityStatus | Unset = UNSET 41 objective: SweepSensitivityObjective | Unset = UNSET 42 rows_analysed: int | Unset = UNSET 43 marginals: list[SweepMarginal] | Unset = UNSET 44 heatmaps: list[SweepHeatmap] | Unset = UNSET 45 heatmaps_truncated: bool | Unset = UNSET 46 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 47 48 def to_dict(self) -> dict[str, Any]: 49 sweep_id = self.sweep_id 50 51 status: str | Unset = UNSET 52 if not isinstance(self.status, Unset): 53 status = self.status.value 54 55 objective: str | Unset = UNSET 56 if not isinstance(self.objective, Unset): 57 objective = self.objective.value 58 59 rows_analysed = self.rows_analysed 60 61 marginals: list[dict[str, Any]] | Unset = UNSET 62 if not isinstance(self.marginals, Unset): 63 marginals = [] 64 for marginals_item_data in self.marginals: 65 marginals_item = marginals_item_data.to_dict() 66 marginals.append(marginals_item) 67 68 heatmaps: list[dict[str, Any]] | Unset = UNSET 69 if not isinstance(self.heatmaps, Unset): 70 heatmaps = [] 71 for heatmaps_item_data in self.heatmaps: 72 heatmaps_item = heatmaps_item_data.to_dict() 73 heatmaps.append(heatmaps_item) 74 75 heatmaps_truncated = self.heatmaps_truncated 76 77 field_dict: dict[str, Any] = {} 78 field_dict.update(self.additional_properties) 79 field_dict.update({}) 80 if sweep_id is not UNSET: 81 field_dict["sweepId"] = sweep_id 82 if status is not UNSET: 83 field_dict["status"] = status 84 if objective is not UNSET: 85 field_dict["objective"] = objective 86 if rows_analysed is not UNSET: 87 field_dict["rowsAnalysed"] = rows_analysed 88 if marginals is not UNSET: 89 field_dict["marginals"] = marginals 90 if heatmaps is not UNSET: 91 field_dict["heatmaps"] = heatmaps 92 if heatmaps_truncated is not UNSET: 93 field_dict["heatmapsTruncated"] = heatmaps_truncated 94 95 return field_dict 96 97 @classmethod 98 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 99 from ..models.sweep_heatmap import SweepHeatmap 100 from ..models.sweep_marginal import SweepMarginal 101 102 d = dict(src_dict) 103 sweep_id = d.pop("sweepId", UNSET) 104 105 _status = d.pop("status", UNSET) 106 status: SweepSensitivityStatus | Unset 107 if isinstance(_status, Unset): 108 status = UNSET 109 else: 110 status = SweepSensitivityStatus(_status) 111 112 _objective = d.pop("objective", UNSET) 113 objective: SweepSensitivityObjective | Unset 114 if isinstance(_objective, Unset): 115 objective = UNSET 116 else: 117 objective = SweepSensitivityObjective(_objective) 118 119 rows_analysed = d.pop("rowsAnalysed", UNSET) 120 121 _marginals = d.pop("marginals", UNSET) 122 marginals: list[SweepMarginal] | Unset = UNSET 123 if _marginals is not UNSET: 124 marginals = [] 125 for marginals_item_data in _marginals: 126 marginals_item = SweepMarginal.from_dict(marginals_item_data) 127 128 marginals.append(marginals_item) 129 130 _heatmaps = d.pop("heatmaps", UNSET) 131 heatmaps: list[SweepHeatmap] | Unset = UNSET 132 if _heatmaps is not UNSET: 133 heatmaps = [] 134 for heatmaps_item_data in _heatmaps: 135 heatmaps_item = SweepHeatmap.from_dict(heatmaps_item_data) 136 137 heatmaps.append(heatmaps_item) 138 139 heatmaps_truncated = d.pop("heatmapsTruncated", UNSET) 140 141 sweep_sensitivity = cls( 142 sweep_id=sweep_id, 143 status=status, 144 objective=objective, 145 rows_analysed=rows_analysed, 146 marginals=marginals, 147 heatmaps=heatmaps, 148 heatmaps_truncated=heatmaps_truncated, 149 ) 150 151 sweep_sensitivity.additional_properties = d 152 return sweep_sensitivity 153 154 @property 155 def additional_keys(self) -> list[str]: 156 return list(self.additional_properties.keys()) 157 158 def __getitem__(self, key: str) -> Any: 159 return self.additional_properties[key] 160 161 def __setitem__(self, key: str, value: Any) -> None: 162 self.additional_properties[key] = value 163 164 def __delitem__(self, key: str) -> None: 165 del self.additional_properties[key] 166 167 def __contains__(self, key: str) -> bool: 168 return key in self.additional_properties
Sensitivity aggregates over a sweep's stored rows. Marginals are always complete; heatmaps may be capped, in which
case heatmapsTruncated is true.
Attributes:
sweep_id (str | Unset):
status (SweepSensitivityStatus | Unset):
objective (SweepSensitivityObjective | Unset):
rows_analysed (int | Unset): Rows available when this was computed. Grows while a sweep is still running.
marginals (list[SweepMarginal] | Unset):
heatmaps (list[SweepHeatmap] | Unset):
heatmaps_truncated (bool | Unset): True when at least one two-parameter surface was left out to stay inside the
response budget. Told explicitly because a silently short list would read as "these are all the interactions",
which is the wrong thing to conclude from a sensitivity view.
30def __init__(self, sweep_id=attr_dict['sweep_id'].default, status=attr_dict['status'].default, objective=attr_dict['objective'].default, rows_analysed=attr_dict['rows_analysed'].default, marginals=attr_dict['marginals'].default, heatmaps=attr_dict['heatmaps'].default, heatmaps_truncated=attr_dict['heatmaps_truncated'].default): 31 self.sweep_id = sweep_id 32 self.status = status 33 self.objective = objective 34 self.rows_analysed = rows_analysed 35 self.marginals = marginals 36 self.heatmaps = heatmaps 37 self.heatmaps_truncated = heatmaps_truncated 38 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepSensitivity.
48 def to_dict(self) -> dict[str, Any]: 49 sweep_id = self.sweep_id 50 51 status: str | Unset = UNSET 52 if not isinstance(self.status, Unset): 53 status = self.status.value 54 55 objective: str | Unset = UNSET 56 if not isinstance(self.objective, Unset): 57 objective = self.objective.value 58 59 rows_analysed = self.rows_analysed 60 61 marginals: list[dict[str, Any]] | Unset = UNSET 62 if not isinstance(self.marginals, Unset): 63 marginals = [] 64 for marginals_item_data in self.marginals: 65 marginals_item = marginals_item_data.to_dict() 66 marginals.append(marginals_item) 67 68 heatmaps: list[dict[str, Any]] | Unset = UNSET 69 if not isinstance(self.heatmaps, Unset): 70 heatmaps = [] 71 for heatmaps_item_data in self.heatmaps: 72 heatmaps_item = heatmaps_item_data.to_dict() 73 heatmaps.append(heatmaps_item) 74 75 heatmaps_truncated = self.heatmaps_truncated 76 77 field_dict: dict[str, Any] = {} 78 field_dict.update(self.additional_properties) 79 field_dict.update({}) 80 if sweep_id is not UNSET: 81 field_dict["sweepId"] = sweep_id 82 if status is not UNSET: 83 field_dict["status"] = status 84 if objective is not UNSET: 85 field_dict["objective"] = objective 86 if rows_analysed is not UNSET: 87 field_dict["rowsAnalysed"] = rows_analysed 88 if marginals is not UNSET: 89 field_dict["marginals"] = marginals 90 if heatmaps is not UNSET: 91 field_dict["heatmaps"] = heatmaps 92 if heatmaps_truncated is not UNSET: 93 field_dict["heatmapsTruncated"] = heatmaps_truncated 94 95 return field_dict
97 @classmethod 98 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 99 from ..models.sweep_heatmap import SweepHeatmap 100 from ..models.sweep_marginal import SweepMarginal 101 102 d = dict(src_dict) 103 sweep_id = d.pop("sweepId", UNSET) 104 105 _status = d.pop("status", UNSET) 106 status: SweepSensitivityStatus | Unset 107 if isinstance(_status, Unset): 108 status = UNSET 109 else: 110 status = SweepSensitivityStatus(_status) 111 112 _objective = d.pop("objective", UNSET) 113 objective: SweepSensitivityObjective | Unset 114 if isinstance(_objective, Unset): 115 objective = UNSET 116 else: 117 objective = SweepSensitivityObjective(_objective) 118 119 rows_analysed = d.pop("rowsAnalysed", UNSET) 120 121 _marginals = d.pop("marginals", UNSET) 122 marginals: list[SweepMarginal] | Unset = UNSET 123 if _marginals is not UNSET: 124 marginals = [] 125 for marginals_item_data in _marginals: 126 marginals_item = SweepMarginal.from_dict(marginals_item_data) 127 128 marginals.append(marginals_item) 129 130 _heatmaps = d.pop("heatmaps", UNSET) 131 heatmaps: list[SweepHeatmap] | Unset = UNSET 132 if _heatmaps is not UNSET: 133 heatmaps = [] 134 for heatmaps_item_data in _heatmaps: 135 heatmaps_item = SweepHeatmap.from_dict(heatmaps_item_data) 136 137 heatmaps.append(heatmaps_item) 138 139 heatmaps_truncated = d.pop("heatmapsTruncated", UNSET) 140 141 sweep_sensitivity = cls( 142 sweep_id=sweep_id, 143 status=status, 144 objective=objective, 145 rows_analysed=rows_analysed, 146 marginals=marginals, 147 heatmaps=heatmaps, 148 heatmaps_truncated=heatmaps_truncated, 149 ) 150 151 sweep_sensitivity.additional_properties = d 152 return sweep_sensitivity
5class SweepSensitivityObjective(str, Enum): 6 MAXDD = "maxdd" 7 PNL = "pnl" 8 SHARPE = "sharpe" 9 SORTINO = "sortino" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
5class SweepSensitivityStatus(str, Enum): 6 CANCELLED = "CANCELLED" 7 COMPLETED = "COMPLETED" 8 PARTIAL = "PARTIAL" 9 RUNNING = "RUNNING" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
21@_attrs_define 22class SweepSpecRequest: 23 """ 24 Example: 25 {'sampler': 'lhs', 'seed': 487221, 'samples': 100, 'objective': 'sharpe', 'params': {'rsiPeriod': {'from': 7, 26 'to': 28, 'step': 1}, 'useTrendFilter': {'values': [True, False]}}} 27 28 Attributes: 29 params (SweepSpecRequestParams): 30 sampler (SweepSpecRequestSampler | Unset): Default: SweepSpecRequestSampler.GRID. 31 seed (int | Unset): Reproducibility seed. If omitted, the server generates one with Java's 32 `L64X128MixRandom` generator and returns the effective value. The range 33 is limited to JavaScript-safe integers so generated clients can replay it exactly. 34 samples (int | Unset): Number of samples for `random` and `lhs`; ignored by `grid`. 35 objective (SweepSpecRequestObjective | Unset): Default: SweepSpecRequestObjective.SHARPE. 36 """ 37 38 params: SweepSpecRequestParams 39 sampler: SweepSpecRequestSampler | Unset = SweepSpecRequestSampler.GRID 40 seed: int | Unset = UNSET 41 samples: int | Unset = UNSET 42 objective: SweepSpecRequestObjective | Unset = SweepSpecRequestObjective.SHARPE 43 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 44 45 def to_dict(self) -> dict[str, Any]: 46 params = self.params.to_dict() 47 48 sampler: str | Unset = UNSET 49 if not isinstance(self.sampler, Unset): 50 sampler = self.sampler.value 51 52 seed = self.seed 53 54 samples = self.samples 55 56 objective: str | Unset = UNSET 57 if not isinstance(self.objective, Unset): 58 objective = self.objective.value 59 60 field_dict: dict[str, Any] = {} 61 field_dict.update(self.additional_properties) 62 field_dict.update( 63 { 64 "params": params, 65 } 66 ) 67 if sampler is not UNSET: 68 field_dict["sampler"] = sampler 69 if seed is not UNSET: 70 field_dict["seed"] = seed 71 if samples is not UNSET: 72 field_dict["samples"] = samples 73 if objective is not UNSET: 74 field_dict["objective"] = objective 75 76 return field_dict 77 78 @classmethod 79 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 80 from ..models.sweep_spec_request_params import SweepSpecRequestParams 81 82 d = dict(src_dict) 83 params = SweepSpecRequestParams.from_dict(d.pop("params")) 84 85 _sampler = d.pop("sampler", UNSET) 86 sampler: SweepSpecRequestSampler | Unset 87 if isinstance(_sampler, Unset): 88 sampler = UNSET 89 else: 90 sampler = SweepSpecRequestSampler(_sampler) 91 92 seed = d.pop("seed", UNSET) 93 94 samples = d.pop("samples", UNSET) 95 96 _objective = d.pop("objective", UNSET) 97 objective: SweepSpecRequestObjective | Unset 98 if isinstance(_objective, Unset): 99 objective = UNSET 100 else: 101 objective = SweepSpecRequestObjective(_objective) 102 103 sweep_spec_request = cls( 104 params=params, 105 sampler=sampler, 106 seed=seed, 107 samples=samples, 108 objective=objective, 109 ) 110 111 sweep_spec_request.additional_properties = d 112 return sweep_spec_request 113 114 @property 115 def additional_keys(self) -> list[str]: 116 return list(self.additional_properties.keys()) 117 118 def __getitem__(self, key: str) -> Any: 119 return self.additional_properties[key] 120 121 def __setitem__(self, key: str, value: Any) -> None: 122 self.additional_properties[key] = value 123 124 def __delitem__(self, key: str) -> None: 125 del self.additional_properties[key] 126 127 def __contains__(self, key: str) -> bool: 128 return key in self.additional_properties
Example: {'sampler': 'lhs', 'seed': 487221, 'samples': 100, 'objective': 'sharpe', 'params': {'rsiPeriod': {'from': 7, 'to': 28, 'step': 1}, 'useTrendFilter': {'values': [True, False]}}}
Attributes:
params (SweepSpecRequestParams):
sampler (SweepSpecRequestSampler | Unset): Default: SweepSpecRequestSampler.GRID.
seed (int | Unset): Reproducibility seed. If omitted, the server generates one with Java's
L64X128MixRandom generator and returns the effective value. The range
is limited to JavaScript-safe integers so generated clients can replay it exactly.
samples (int | Unset): Number of samples for random and lhs; ignored by grid.
objective (SweepSpecRequestObjective | Unset): Default: SweepSpecRequestObjective.SHARPE.
28def __init__(self, params, sampler=attr_dict['sampler'].default, seed=attr_dict['seed'].default, samples=attr_dict['samples'].default, objective=attr_dict['objective'].default): 29 self.params = params 30 self.sampler = sampler 31 self.seed = seed 32 self.samples = samples 33 self.objective = objective 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class SweepSpecRequest.
45 def to_dict(self) -> dict[str, Any]: 46 params = self.params.to_dict() 47 48 sampler: str | Unset = UNSET 49 if not isinstance(self.sampler, Unset): 50 sampler = self.sampler.value 51 52 seed = self.seed 53 54 samples = self.samples 55 56 objective: str | Unset = UNSET 57 if not isinstance(self.objective, Unset): 58 objective = self.objective.value 59 60 field_dict: dict[str, Any] = {} 61 field_dict.update(self.additional_properties) 62 field_dict.update( 63 { 64 "params": params, 65 } 66 ) 67 if sampler is not UNSET: 68 field_dict["sampler"] = sampler 69 if seed is not UNSET: 70 field_dict["seed"] = seed 71 if samples is not UNSET: 72 field_dict["samples"] = samples 73 if objective is not UNSET: 74 field_dict["objective"] = objective 75 76 return field_dict
78 @classmethod 79 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 80 from ..models.sweep_spec_request_params import SweepSpecRequestParams 81 82 d = dict(src_dict) 83 params = SweepSpecRequestParams.from_dict(d.pop("params")) 84 85 _sampler = d.pop("sampler", UNSET) 86 sampler: SweepSpecRequestSampler | Unset 87 if isinstance(_sampler, Unset): 88 sampler = UNSET 89 else: 90 sampler = SweepSpecRequestSampler(_sampler) 91 92 seed = d.pop("seed", UNSET) 93 94 samples = d.pop("samples", UNSET) 95 96 _objective = d.pop("objective", UNSET) 97 objective: SweepSpecRequestObjective | Unset 98 if isinstance(_objective, Unset): 99 objective = UNSET 100 else: 101 objective = SweepSpecRequestObjective(_objective) 102 103 sweep_spec_request = cls( 104 params=params, 105 sampler=sampler, 106 seed=seed, 107 samples=samples, 108 objective=objective, 109 ) 110 111 sweep_spec_request.additional_properties = d 112 return sweep_spec_request
5class SweepSpecRequestObjective(str, Enum): 6 MAXDD = "maxdd" 7 PNL = "pnl" 8 SHARPE = "sharpe" 9 SORTINO = "sortino" 10 11 def __str__(self) -> str: 12 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
18@_attrs_define 19class SweepSpecRequestParams: 20 """ """ 21 22 additional_properties: dict[str, SweepAxisType0 | SweepAxisType1] = _attrs_field(init=False, factory=dict) 23 24 def to_dict(self) -> dict[str, Any]: 25 from ..models.sweep_axis_type_0 import SweepAxisType0 26 27 field_dict: dict[str, Any] = {} 28 for prop_name, prop in self.additional_properties.items(): 29 if isinstance(prop, SweepAxisType0): 30 field_dict[prop_name] = prop.to_dict() 31 else: 32 field_dict[prop_name] = prop.to_dict() 33 34 return field_dict 35 36 @classmethod 37 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 38 from ..models.sweep_axis_type_0 import SweepAxisType0 39 from ..models.sweep_axis_type_1 import SweepAxisType1 40 41 d = dict(src_dict) 42 sweep_spec_request_params = cls() 43 44 additional_properties = {} 45 for prop_name, prop_dict in d.items(): 46 47 def _parse_additional_property(data: object) -> SweepAxisType0 | SweepAxisType1: 48 try: 49 if not isinstance(data, dict): 50 raise TypeError() 51 componentsschemas_sweep_axis_type_0 = SweepAxisType0.from_dict(data) 52 53 return componentsschemas_sweep_axis_type_0 54 except (TypeError, ValueError, AttributeError, KeyError): 55 pass 56 if not isinstance(data, dict): 57 raise TypeError() 58 componentsschemas_sweep_axis_type_1 = SweepAxisType1.from_dict(data) 59 60 return componentsschemas_sweep_axis_type_1 61 62 additional_property = _parse_additional_property(prop_dict) 63 64 additional_properties[prop_name] = additional_property 65 66 sweep_spec_request_params.additional_properties = additional_properties 67 return sweep_spec_request_params 68 69 @property 70 def additional_keys(self) -> list[str]: 71 return list(self.additional_properties.keys()) 72 73 def __getitem__(self, key: str) -> SweepAxisType0 | SweepAxisType1: 74 return self.additional_properties[key] 75 76 def __setitem__(self, key: str, value: SweepAxisType0 | SweepAxisType1) -> None: 77 self.additional_properties[key] = value 78 79 def __delitem__(self, key: str) -> None: 80 del self.additional_properties[key] 81 82 def __contains__(self, key: str) -> bool: 83 return key in self.additional_properties
24 def to_dict(self) -> dict[str, Any]: 25 from ..models.sweep_axis_type_0 import SweepAxisType0 26 27 field_dict: dict[str, Any] = {} 28 for prop_name, prop in self.additional_properties.items(): 29 if isinstance(prop, SweepAxisType0): 30 field_dict[prop_name] = prop.to_dict() 31 else: 32 field_dict[prop_name] = prop.to_dict() 33 34 return field_dict
36 @classmethod 37 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 38 from ..models.sweep_axis_type_0 import SweepAxisType0 39 from ..models.sweep_axis_type_1 import SweepAxisType1 40 41 d = dict(src_dict) 42 sweep_spec_request_params = cls() 43 44 additional_properties = {} 45 for prop_name, prop_dict in d.items(): 46 47 def _parse_additional_property(data: object) -> SweepAxisType0 | SweepAxisType1: 48 try: 49 if not isinstance(data, dict): 50 raise TypeError() 51 componentsschemas_sweep_axis_type_0 = SweepAxisType0.from_dict(data) 52 53 return componentsschemas_sweep_axis_type_0 54 except (TypeError, ValueError, AttributeError, KeyError): 55 pass 56 if not isinstance(data, dict): 57 raise TypeError() 58 componentsschemas_sweep_axis_type_1 = SweepAxisType1.from_dict(data) 59 60 return componentsschemas_sweep_axis_type_1 61 62 additional_property = _parse_additional_property(prop_dict) 63 64 additional_properties[prop_name] = additional_property 65 66 sweep_spec_request_params.additional_properties = additional_properties 67 return sweep_spec_request_params
5class SweepSpecRequestSampler(str, Enum): 6 GRID = "grid" 7 LHS = "lhs" 8 RANDOM = "random" 9 10 def __str__(self) -> str: 11 return str(self.value)
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
13@_attrs_define 14class WalkForwardAccepted: 15 """Echo of the accepted walk-forward configuration, present only when the submit carried one. `inSamplePct` is the 16 resolved value, so a request that omitted it can see what it got. 17 18 Attributes: 19 folds (int): 20 in_sample_pct (int): 21 total_runs (int): What this sweep actually costs, `folds × (grid size + 1)` — the in-sample runs for every fold 22 plus each fold's one out-of-sample run. Deliberately distinct from the top-level `totalRuns`, which stays the 23 size of the grid that was submitted. 24 """ 25 26 folds: int 27 in_sample_pct: int 28 total_runs: int 29 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 30 31 def to_dict(self) -> dict[str, Any]: 32 folds = self.folds 33 34 in_sample_pct = self.in_sample_pct 35 36 total_runs = self.total_runs 37 38 field_dict: dict[str, Any] = {} 39 field_dict.update(self.additional_properties) 40 field_dict.update( 41 { 42 "folds": folds, 43 "inSamplePct": in_sample_pct, 44 "totalRuns": total_runs, 45 } 46 ) 47 48 return field_dict 49 50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 d = dict(src_dict) 53 folds = d.pop("folds") 54 55 in_sample_pct = d.pop("inSamplePct") 56 57 total_runs = d.pop("totalRuns") 58 59 walk_forward_accepted = cls( 60 folds=folds, 61 in_sample_pct=in_sample_pct, 62 total_runs=total_runs, 63 ) 64 65 walk_forward_accepted.additional_properties = d 66 return walk_forward_accepted 67 68 @property 69 def additional_keys(self) -> list[str]: 70 return list(self.additional_properties.keys()) 71 72 def __getitem__(self, key: str) -> Any: 73 return self.additional_properties[key] 74 75 def __setitem__(self, key: str, value: Any) -> None: 76 self.additional_properties[key] = value 77 78 def __delitem__(self, key: str) -> None: 79 del self.additional_properties[key] 80 81 def __contains__(self, key: str) -> bool: 82 return key in self.additional_properties
Echo of the accepted walk-forward configuration, present only when the submit carried one. inSamplePct is the
resolved value, so a request that omitted it can see what it got.
Attributes:
folds (int):
in_sample_pct (int):
total_runs (int): What this sweep actually costs, `folds × (grid size + 1)` — the in-sample runs for every fold
plus each fold's one out-of-sample run. Deliberately distinct from the top-level `totalRuns`, which stays the
size of the grid that was submitted.
26def __init__(self, folds, in_sample_pct, total_runs): 27 self.folds = folds 28 self.in_sample_pct = in_sample_pct 29 self.total_runs = total_runs 30 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class WalkForwardAccepted.
31 def to_dict(self) -> dict[str, Any]: 32 folds = self.folds 33 34 in_sample_pct = self.in_sample_pct 35 36 total_runs = self.total_runs 37 38 field_dict: dict[str, Any] = {} 39 field_dict.update(self.additional_properties) 40 field_dict.update( 41 { 42 "folds": folds, 43 "inSamplePct": in_sample_pct, 44 "totalRuns": total_runs, 45 } 46 ) 47 48 return field_dict
50 @classmethod 51 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 52 d = dict(src_dict) 53 folds = d.pop("folds") 54 55 in_sample_pct = d.pop("inSamplePct") 56 57 total_runs = d.pop("totalRuns") 58 59 walk_forward_accepted = cls( 60 folds=folds, 61 in_sample_pct=in_sample_pct, 62 total_runs=total_runs, 63 ) 64 65 walk_forward_accepted.additional_properties = d 66 return walk_forward_accepted
18@_attrs_define 19class WalkForwardFold: 20 """What one fold concluded. The out-of-sample row is the answer; the in-sample figure is only there to be compared 21 against it, since any grid produces a flattering in-sample winner — that is what optimizing does. The gap between 22 them is the whole reading. 23 24 Attributes: 25 fold_ix (int): Position in the walk-forward sequence, oldest first. 26 in_sample_from (int): First index of the optimization window, into the prepared session. 27 in_sample_to (int): End of the optimization window, exclusive — and where scoring begins. 28 out_of_sample_to (int): End of the scoring window, exclusive. 29 params (WalkForwardFoldParams): The parameter vector that won this fold's optimization window. 30 in_sample_sharpe (float): How that winner scored on the window it was chosen on. 31 out_of_sample (SweepRunRow): 32 vectors_run (int): Vectors this fold evaluated in-sample before picking its winner. 33 """ 34 35 fold_ix: int 36 in_sample_from: int 37 in_sample_to: int 38 out_of_sample_to: int 39 params: WalkForwardFoldParams 40 in_sample_sharpe: float 41 out_of_sample: SweepRunRow 42 vectors_run: int 43 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 44 45 def to_dict(self) -> dict[str, Any]: 46 fold_ix = self.fold_ix 47 48 in_sample_from = self.in_sample_from 49 50 in_sample_to = self.in_sample_to 51 52 out_of_sample_to = self.out_of_sample_to 53 54 params = self.params.to_dict() 55 56 in_sample_sharpe = self.in_sample_sharpe 57 58 out_of_sample = self.out_of_sample.to_dict() 59 60 vectors_run = self.vectors_run 61 62 field_dict: dict[str, Any] = {} 63 field_dict.update(self.additional_properties) 64 field_dict.update( 65 { 66 "foldIx": fold_ix, 67 "inSampleFrom": in_sample_from, 68 "inSampleTo": in_sample_to, 69 "outOfSampleTo": out_of_sample_to, 70 "params": params, 71 "inSampleSharpe": in_sample_sharpe, 72 "outOfSample": out_of_sample, 73 "vectorsRun": vectors_run, 74 } 75 ) 76 77 return field_dict 78 79 @classmethod 80 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 81 from ..models.sweep_run_row import SweepRunRow 82 from ..models.walk_forward_fold_params import WalkForwardFoldParams 83 84 d = dict(src_dict) 85 fold_ix = d.pop("foldIx") 86 87 in_sample_from = d.pop("inSampleFrom") 88 89 in_sample_to = d.pop("inSampleTo") 90 91 out_of_sample_to = d.pop("outOfSampleTo") 92 93 params = WalkForwardFoldParams.from_dict(d.pop("params")) 94 95 in_sample_sharpe = d.pop("inSampleSharpe") 96 97 out_of_sample = SweepRunRow.from_dict(d.pop("outOfSample")) 98 99 vectors_run = d.pop("vectorsRun") 100 101 walk_forward_fold = cls( 102 fold_ix=fold_ix, 103 in_sample_from=in_sample_from, 104 in_sample_to=in_sample_to, 105 out_of_sample_to=out_of_sample_to, 106 params=params, 107 in_sample_sharpe=in_sample_sharpe, 108 out_of_sample=out_of_sample, 109 vectors_run=vectors_run, 110 ) 111 112 walk_forward_fold.additional_properties = d 113 return walk_forward_fold 114 115 @property 116 def additional_keys(self) -> list[str]: 117 return list(self.additional_properties.keys()) 118 119 def __getitem__(self, key: str) -> Any: 120 return self.additional_properties[key] 121 122 def __setitem__(self, key: str, value: Any) -> None: 123 self.additional_properties[key] = value 124 125 def __delitem__(self, key: str) -> None: 126 del self.additional_properties[key] 127 128 def __contains__(self, key: str) -> bool: 129 return key in self.additional_properties
What one fold concluded. The out-of-sample row is the answer; the in-sample figure is only there to be compared against it, since any grid produces a flattering in-sample winner — that is what optimizing does. The gap between them is the whole reading.
Attributes:
fold_ix (int): Position in the walk-forward sequence, oldest first.
in_sample_from (int): First index of the optimization window, into the prepared session.
in_sample_to (int): End of the optimization window, exclusive — and where scoring begins.
out_of_sample_to (int): End of the scoring window, exclusive.
params (WalkForwardFoldParams): The parameter vector that won this fold's optimization window.
in_sample_sharpe (float): How that winner scored on the window it was chosen on.
out_of_sample (SweepRunRow):
vectors_run (int): Vectors this fold evaluated in-sample before picking its winner.
31def __init__(self, fold_ix, in_sample_from, in_sample_to, out_of_sample_to, params, in_sample_sharpe, out_of_sample, vectors_run): 32 self.fold_ix = fold_ix 33 self.in_sample_from = in_sample_from 34 self.in_sample_to = in_sample_to 35 self.out_of_sample_to = out_of_sample_to 36 self.params = params 37 self.in_sample_sharpe = in_sample_sharpe 38 self.out_of_sample = out_of_sample 39 self.vectors_run = vectors_run 40 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class WalkForwardFold.
45 def to_dict(self) -> dict[str, Any]: 46 fold_ix = self.fold_ix 47 48 in_sample_from = self.in_sample_from 49 50 in_sample_to = self.in_sample_to 51 52 out_of_sample_to = self.out_of_sample_to 53 54 params = self.params.to_dict() 55 56 in_sample_sharpe = self.in_sample_sharpe 57 58 out_of_sample = self.out_of_sample.to_dict() 59 60 vectors_run = self.vectors_run 61 62 field_dict: dict[str, Any] = {} 63 field_dict.update(self.additional_properties) 64 field_dict.update( 65 { 66 "foldIx": fold_ix, 67 "inSampleFrom": in_sample_from, 68 "inSampleTo": in_sample_to, 69 "outOfSampleTo": out_of_sample_to, 70 "params": params, 71 "inSampleSharpe": in_sample_sharpe, 72 "outOfSample": out_of_sample, 73 "vectorsRun": vectors_run, 74 } 75 ) 76 77 return field_dict
79 @classmethod 80 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 81 from ..models.sweep_run_row import SweepRunRow 82 from ..models.walk_forward_fold_params import WalkForwardFoldParams 83 84 d = dict(src_dict) 85 fold_ix = d.pop("foldIx") 86 87 in_sample_from = d.pop("inSampleFrom") 88 89 in_sample_to = d.pop("inSampleTo") 90 91 out_of_sample_to = d.pop("outOfSampleTo") 92 93 params = WalkForwardFoldParams.from_dict(d.pop("params")) 94 95 in_sample_sharpe = d.pop("inSampleSharpe") 96 97 out_of_sample = SweepRunRow.from_dict(d.pop("outOfSample")) 98 99 vectors_run = d.pop("vectorsRun") 100 101 walk_forward_fold = cls( 102 fold_ix=fold_ix, 103 in_sample_from=in_sample_from, 104 in_sample_to=in_sample_to, 105 out_of_sample_to=out_of_sample_to, 106 params=params, 107 in_sample_sharpe=in_sample_sharpe, 108 out_of_sample=out_of_sample, 109 vectors_run=vectors_run, 110 ) 111 112 walk_forward_fold.additional_properties = d 113 return walk_forward_fold
13@_attrs_define 14class WalkForwardFoldParams: 15 """The parameter vector that won this fold's optimization window.""" 16 17 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 18 19 def to_dict(self) -> dict[str, Any]: 20 21 field_dict: dict[str, Any] = {} 22 field_dict.update(self.additional_properties) 23 24 return field_dict 25 26 @classmethod 27 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 28 d = dict(src_dict) 29 walk_forward_fold_params = cls() 30 31 walk_forward_fold_params.additional_properties = d 32 return walk_forward_fold_params 33 34 @property 35 def additional_keys(self) -> list[str]: 36 return list(self.additional_properties.keys()) 37 38 def __getitem__(self, key: str) -> Any: 39 return self.additional_properties[key] 40 41 def __setitem__(self, key: str, value: Any) -> None: 42 self.additional_properties[key] = value 43 44 def __delitem__(self, key: str) -> None: 45 del self.additional_properties[key] 46 47 def __contains__(self, key: str) -> bool: 48 return key in self.additional_properties
The parameter vector that won this fold's optimization window.
15@_attrs_define 16class WalkForwardRequest: 17 """Opt in to walk-forward validation. Present, the sweep runs as F sequential folds and the result gains a 18 `walkForward` section; absent, nothing about the sweep changes. Two requests that differ only in this block are two 19 different sweeps and do not deduplicate against each other. 20 21 Attributes: 22 folds (int): How many sequential optimize-then-score windows to run. Two is the minimum for a reason, and it is 23 structural rather than a tuning choice: parameter drift is measured between consecutive fold winners, and a 24 single fold — one train/test split with no sequence — has no consecutive pair to compare, so it would report the 25 strongest possible stability having measured nothing. 26 The upper bound is a server setting (12 by default) and is deliberately not pinned here, since a spec that 27 hardcodes a tunable limit lies the day it is raised. Exceeding it, or exceeding the sweep budget once multiplied 28 by the grid size, is a 400. 29 in_sample_pct (int | Unset): Share of the session each fold spends optimizing; the remainder is where its winner 30 is scored. Lower values leave more data to be scored on and, on short sessions, are also what lets the requested 31 fold count tile the data at all. Default: 66. 32 """ 33 34 folds: int 35 in_sample_pct: int | Unset = 66 36 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 37 38 def to_dict(self) -> dict[str, Any]: 39 folds = self.folds 40 41 in_sample_pct = self.in_sample_pct 42 43 field_dict: dict[str, Any] = {} 44 field_dict.update(self.additional_properties) 45 field_dict.update( 46 { 47 "folds": folds, 48 } 49 ) 50 if in_sample_pct is not UNSET: 51 field_dict["inSamplePct"] = in_sample_pct 52 53 return field_dict 54 55 @classmethod 56 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 57 d = dict(src_dict) 58 folds = d.pop("folds") 59 60 in_sample_pct = d.pop("inSamplePct", UNSET) 61 62 walk_forward_request = cls( 63 folds=folds, 64 in_sample_pct=in_sample_pct, 65 ) 66 67 walk_forward_request.additional_properties = d 68 return walk_forward_request 69 70 @property 71 def additional_keys(self) -> list[str]: 72 return list(self.additional_properties.keys()) 73 74 def __getitem__(self, key: str) -> Any: 75 return self.additional_properties[key] 76 77 def __setitem__(self, key: str, value: Any) -> None: 78 self.additional_properties[key] = value 79 80 def __delitem__(self, key: str) -> None: 81 del self.additional_properties[key] 82 83 def __contains__(self, key: str) -> bool: 84 return key in self.additional_properties
Opt in to walk-forward validation. Present, the sweep runs as F sequential folds and the result gains a
walkForward section; absent, nothing about the sweep changes. Two requests that differ only in this block are two
different sweeps and do not deduplicate against each other.
Attributes:
folds (int): How many sequential optimize-then-score windows to run. Two is the minimum for a reason, and it is
structural rather than a tuning choice: parameter drift is measured between consecutive fold winners, and a
single fold — one train/test split with no sequence — has no consecutive pair to compare, so it would report the
strongest possible stability having measured nothing.
The upper bound is a server setting (12 by default) and is deliberately not pinned here, since a spec that
hardcodes a tunable limit lies the day it is raised. Exceeding it, or exceeding the sweep budget once multiplied
by the grid size, is a 400.
in_sample_pct (int | Unset): Share of the session each fold spends optimizing; the remainder is where its winner
is scored. Lower values leave more data to be scored on and, on short sessions, are also what lets the requested
fold count tile the data at all. Default: 66.
25def __init__(self, folds, in_sample_pct=attr_dict['in_sample_pct'].default): 26 self.folds = folds 27 self.in_sample_pct = in_sample_pct 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class WalkForwardRequest.
38 def to_dict(self) -> dict[str, Any]: 39 folds = self.folds 40 41 in_sample_pct = self.in_sample_pct 42 43 field_dict: dict[str, Any] = {} 44 field_dict.update(self.additional_properties) 45 field_dict.update( 46 { 47 "folds": folds, 48 } 49 ) 50 if in_sample_pct is not UNSET: 51 field_dict["inSamplePct"] = in_sample_pct 52 53 return field_dict
55 @classmethod 56 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 57 d = dict(src_dict) 58 folds = d.pop("folds") 59 60 in_sample_pct = d.pop("inSamplePct", UNSET) 61 62 walk_forward_request = cls( 63 folds=folds, 64 in_sample_pct=in_sample_pct, 65 ) 66 67 walk_forward_request.additional_properties = d 68 return walk_forward_request
19@_attrs_define 20class WalkForwardResult: 21 """Present only on a sweep submitted with `walkForward`, and present from acceptance onward — its presence, not its 22 contents, is what identifies a walk-forward sweep. `completedFolds` is 0 while the first fold is still running. 23 24 Attributes: 25 folds (int): Folds requested at submit. 26 completed_folds (int): Folds that have finished and reported a winner. 27 results (list[WalkForwardFold]): One entry per completed fold, oldest first. 28 in_sample_pct (int | Unset): Resolved in-sample share each fold optimized on. 29 param_drift (float | Unset): Mean normalized lattice distance between consecutive fold winners. Low is good: 30 winners that stay in a tight band fold after fold are evidence the parameter means something, while winners that 31 jump across the grid every time are the sweep re-fitting noise, and that backtest will not survive contact with 32 live data. **Absent is not zero** — the field is omitted whenever the figure could not be computed (fewer than 33 two folds finished, no stored grid to place winners on), because zero is itself a meaningful reading here and a 34 placeholder would be indistinguishable from perfect stability. 35 """ 36 37 folds: int 38 completed_folds: int 39 results: list[WalkForwardFold] 40 in_sample_pct: int | Unset = UNSET 41 param_drift: float | Unset = UNSET 42 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 43 44 def to_dict(self) -> dict[str, Any]: 45 folds = self.folds 46 47 completed_folds = self.completed_folds 48 49 results = [] 50 for results_item_data in self.results: 51 results_item = results_item_data.to_dict() 52 results.append(results_item) 53 54 in_sample_pct = self.in_sample_pct 55 56 param_drift = self.param_drift 57 58 field_dict: dict[str, Any] = {} 59 field_dict.update(self.additional_properties) 60 field_dict.update( 61 { 62 "folds": folds, 63 "completedFolds": completed_folds, 64 "results": results, 65 } 66 ) 67 if in_sample_pct is not UNSET: 68 field_dict["inSamplePct"] = in_sample_pct 69 if param_drift is not UNSET: 70 field_dict["paramDrift"] = param_drift 71 72 return field_dict 73 74 @classmethod 75 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 76 from ..models.walk_forward_fold import WalkForwardFold 77 78 d = dict(src_dict) 79 folds = d.pop("folds") 80 81 completed_folds = d.pop("completedFolds") 82 83 results = [] 84 _results = d.pop("results") 85 for results_item_data in _results: 86 results_item = WalkForwardFold.from_dict(results_item_data) 87 88 results.append(results_item) 89 90 in_sample_pct = d.pop("inSamplePct", UNSET) 91 92 param_drift = d.pop("paramDrift", UNSET) 93 94 walk_forward_result = cls( 95 folds=folds, 96 completed_folds=completed_folds, 97 results=results, 98 in_sample_pct=in_sample_pct, 99 param_drift=param_drift, 100 ) 101 102 walk_forward_result.additional_properties = d 103 return walk_forward_result 104 105 @property 106 def additional_keys(self) -> list[str]: 107 return list(self.additional_properties.keys()) 108 109 def __getitem__(self, key: str) -> Any: 110 return self.additional_properties[key] 111 112 def __setitem__(self, key: str, value: Any) -> None: 113 self.additional_properties[key] = value 114 115 def __delitem__(self, key: str) -> None: 116 del self.additional_properties[key] 117 118 def __contains__(self, key: str) -> bool: 119 return key in self.additional_properties
Present only on a sweep submitted with walkForward, and present from acceptance onward — its presence, not its
contents, is what identifies a walk-forward sweep. completedFolds is 0 while the first fold is still running.
Attributes:
folds (int): Folds requested at submit.
completed_folds (int): Folds that have finished and reported a winner.
results (list[WalkForwardFold]): One entry per completed fold, oldest first.
in_sample_pct (int | Unset): Resolved in-sample share each fold optimized on.
param_drift (float | Unset): Mean normalized lattice distance between consecutive fold winners. Low is good:
winners that stay in a tight band fold after fold are evidence the parameter means something, while winners that
jump across the grid every time are the sweep re-fitting noise, and that backtest will not survive contact with
live data. **Absent is not zero** — the field is omitted whenever the figure could not be computed (fewer than
two folds finished, no stored grid to place winners on), because zero is itself a meaningful reading here and a
placeholder would be indistinguishable from perfect stability.
28def __init__(self, folds, completed_folds, results, in_sample_pct=attr_dict['in_sample_pct'].default, param_drift=attr_dict['param_drift'].default): 29 self.folds = folds 30 self.completed_folds = completed_folds 31 self.results = results 32 self.in_sample_pct = in_sample_pct 33 self.param_drift = param_drift 34 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class WalkForwardResult.
44 def to_dict(self) -> dict[str, Any]: 45 folds = self.folds 46 47 completed_folds = self.completed_folds 48 49 results = [] 50 for results_item_data in self.results: 51 results_item = results_item_data.to_dict() 52 results.append(results_item) 53 54 in_sample_pct = self.in_sample_pct 55 56 param_drift = self.param_drift 57 58 field_dict: dict[str, Any] = {} 59 field_dict.update(self.additional_properties) 60 field_dict.update( 61 { 62 "folds": folds, 63 "completedFolds": completed_folds, 64 "results": results, 65 } 66 ) 67 if in_sample_pct is not UNSET: 68 field_dict["inSamplePct"] = in_sample_pct 69 if param_drift is not UNSET: 70 field_dict["paramDrift"] = param_drift 71 72 return field_dict
74 @classmethod 75 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 76 from ..models.walk_forward_fold import WalkForwardFold 77 78 d = dict(src_dict) 79 folds = d.pop("folds") 80 81 completed_folds = d.pop("completedFolds") 82 83 results = [] 84 _results = d.pop("results") 85 for results_item_data in _results: 86 results_item = WalkForwardFold.from_dict(results_item_data) 87 88 results.append(results_item) 89 90 in_sample_pct = d.pop("inSamplePct", UNSET) 91 92 param_drift = d.pop("paramDrift", UNSET) 93 94 walk_forward_result = cls( 95 folds=folds, 96 completed_folds=completed_folds, 97 results=results, 98 in_sample_pct=in_sample_pct, 99 param_drift=param_drift, 100 ) 101 102 walk_forward_result.additional_properties = d 103 return walk_forward_result