qtsurfer.api.client.models

Re-export of every generated model plus public scalar aliases.

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 plus public scalar aliases.
 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 typing import TypeAlias
 9
10from qtsurfer.api.client._generated.models import *  # noqa: F401,F403
11from qtsurfer.api.client._generated.models import __all__ as _generated_all
12
13# The generator flattens a named primitive-only `oneOf` schema while it builds
14# map values. Keep the spec name available to consumers at the public facade.
15ScalarStrategyParamValue: TypeAlias = bool | float | str
16
17__all__ = (*_generated_all, "ScalarStrategyParamValue")
class AcceptedJob:
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. For a sweep, pass this same value as the
23                `requestId` path parameter to `executeSweep` — same identifier, different name at that call site. Example:
24                13RBLGQlPnfDjO6wyKSX8i.
25    """
26
27    job_id: str
28    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
29
30    def to_dict(self) -> dict[str, Any]:
31        job_id = self.job_id
32
33        field_dict: dict[str, Any] = {}
34        field_dict.update(self.additional_properties)
35        field_dict.update(
36            {
37                "jobId": job_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        job_id = d.pop("jobId")
47
48        accepted_job = cls(
49            job_id=job_id,
50        )
51
52        accepted_job.additional_properties = d
53        return accepted_job
54
55    @property
56    def additional_keys(self) -> list[str]:
57        return list(self.additional_properties.keys())
58
59    def __getitem__(self, key: str) -> Any:
60        return self.additional_properties[key]
61
62    def __setitem__(self, key: str, value: Any) -> None:
63        self.additional_properties[key] = value
64
65    def __delitem__(self, key: str) -> None:
66        del self.additional_properties[key]
67
68    def __contains__(self, key: str) -> bool:
69        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. For a sweep, pass this same value as the
        `requestId` path parameter to `executeSweep` — same identifier, different name at that call site. Example:
        13RBLGQlPnfDjO6wyKSX8i.
AcceptedJob(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 AcceptedJob.

job_id: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
30    def to_dict(self) -> dict[str, Any]:
31        job_id = self.job_id
32
33        field_dict: dict[str, Any] = {}
34        field_dict.update(self.additional_properties)
35        field_dict.update(
36            {
37                "jobId": job_id,
38            }
39        )
40
41        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
43    @classmethod
44    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
45        d = dict(src_dict)
46        job_id = d.pop("jobId")
47
48        accepted_job = cls(
49            job_id=job_id,
50        )
51
52        accepted_job.additional_properties = d
53        return accepted_job
additional_keys: list[str]
55    @property
56    def additional_keys(self) -> list[str]:
57        return list(self.additional_properties.keys())
class Account:
 17@_attrs_define
 18class Account:
 19    """Your identity and tier limits. No database call behind this one — safe to fetch on every
 20    page load. Live usage against these limits is a separate resource, `GET /account/usage`,
 21    deliberately: usage changes on every upload/execution and costs a query to compute, this
 22    one doesn't.
 23
 24        Attributes:
 25            user_id (str): Your account id — the JWT `sub` claim. Example: 00000000-0000-0000-0000-000000000000.
 26            tier (str): Your current subscription tier. Example: free.
 27            max_execute (int): Maximum number of strategy executions (and sweeps) you can have running at the same time
 28                through the API. Starting one past this number is answered with `429`, whose message
 29                carries the same number. The value already includes any API allowance your plan has.
 30                 Example: 10.
 31            max_range_days (int): Maximum length, in days, of the time range of a backtest on one of your own datasets.
 32                Example: 7.
 33            max_sweep_cartesian (int): Largest full grid, in parameter combinations, a sweep may run with the `grid`
 34                sampler.
 35                A grid with more combinations is refused with `400`; the `random` and `lhs` samplers run
 36                only their `samples` and are not held to it.
 37                 Example: 100.
 38            max_import_range_hours (int): Maximum length, in hours, of the time range of one dataset import from an
 39                exchange. Example: 6.
 40            max_datasets (int): Maximum number of active datasets your tier allows. Example: 3.
 41            max_dataset_bytes (int): Maximum size, in bytes, of a single dataset version as stored, that is the `bytes` of
 42                its ready version. For a CSV upload that is the converted file, not the file you upload, so estimate from the
 43                number of rows. The Datasets guide has the details. Example: 52428800.
 44            max_total_storage_bytes (int): Maximum combined storage, in bytes, across every dataset, strategy-execution
 45                signal,
 46                and registered strategy on your account — one shared pool, not a separate cap per
 47                resource type, since they all compete for the same underlying storage. See `GET
 48                /account/usage`'s `storageBytesUsed` for your current usage against this number.
 49                 Example: 104857600.
 50            field_links (AccountLinks): HAL `_links` for `GET /account`
 51    """
 52
 53    user_id: str
 54    tier: str
 55    max_execute: int
 56    max_range_days: int
 57    max_sweep_cartesian: int
 58    max_import_range_hours: int
 59    max_datasets: int
 60    max_dataset_bytes: int
 61    max_total_storage_bytes: int
 62    field_links: AccountLinks
 63    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 64
 65    def to_dict(self) -> dict[str, Any]:
 66        user_id = self.user_id
 67
 68        tier = self.tier
 69
 70        max_execute = self.max_execute
 71
 72        max_range_days = self.max_range_days
 73
 74        max_sweep_cartesian = self.max_sweep_cartesian
 75
 76        max_import_range_hours = self.max_import_range_hours
 77
 78        max_datasets = self.max_datasets
 79
 80        max_dataset_bytes = self.max_dataset_bytes
 81
 82        max_total_storage_bytes = self.max_total_storage_bytes
 83
 84        field_links = self.field_links.to_dict()
 85
 86        field_dict: dict[str, Any] = {}
 87        field_dict.update(self.additional_properties)
 88        field_dict.update(
 89            {
 90                "userId": user_id,
 91                "tier": tier,
 92                "maxExecute": max_execute,
 93                "maxRangeDays": max_range_days,
 94                "maxSweepCartesian": max_sweep_cartesian,
 95                "maxImportRangeHours": max_import_range_hours,
 96                "maxDatasets": max_datasets,
 97                "maxDatasetBytes": max_dataset_bytes,
 98                "maxTotalStorageBytes": max_total_storage_bytes,
 99                "_links": field_links,
100            }
101        )
102
103        return field_dict
104
105    @classmethod
106    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
107        from ..models.account_links import AccountLinks
108
109        d = dict(src_dict)
110        user_id = d.pop("userId")
111
112        tier = d.pop("tier")
113
114        max_execute = d.pop("maxExecute")
115
116        max_range_days = d.pop("maxRangeDays")
117
118        max_sweep_cartesian = d.pop("maxSweepCartesian")
119
120        max_import_range_hours = d.pop("maxImportRangeHours")
121
122        max_datasets = d.pop("maxDatasets")
123
124        max_dataset_bytes = d.pop("maxDatasetBytes")
125
126        max_total_storage_bytes = d.pop("maxTotalStorageBytes")
127
128        field_links = AccountLinks.from_dict(d.pop("_links"))
129
130        account = cls(
131            user_id=user_id,
132            tier=tier,
133            max_execute=max_execute,
134            max_range_days=max_range_days,
135            max_sweep_cartesian=max_sweep_cartesian,
136            max_import_range_hours=max_import_range_hours,
137            max_datasets=max_datasets,
138            max_dataset_bytes=max_dataset_bytes,
139            max_total_storage_bytes=max_total_storage_bytes,
140            field_links=field_links,
141        )
142
143        account.additional_properties = d
144        return account
145
146    @property
147    def additional_keys(self) -> list[str]:
148        return list(self.additional_properties.keys())
149
150    def __getitem__(self, key: str) -> Any:
151        return self.additional_properties[key]
152
153    def __setitem__(self, key: str, value: Any) -> None:
154        self.additional_properties[key] = value
155
156    def __delitem__(self, key: str) -> None:
157        del self.additional_properties[key]
158
159    def __contains__(self, key: str) -> bool:
160        return key in self.additional_properties

Your identity and tier limits. No database call behind this one — safe to fetch on every page load. Live usage against these limits is a separate resource, GET /account/usage, deliberately: usage changes on every upload/execution and costs a query to compute, this one doesn't.

Attributes:
    user_id (str): Your account id — the JWT `sub` claim. Example: 00000000-0000-0000-0000-000000000000.
    tier (str): Your current subscription tier. Example: free.
    max_execute (int): Maximum number of strategy executions (and sweeps) you can have running at the same time
        through the API. Starting one past this number is answered with `429`, whose message
        carries the same number. The value already includes any API allowance your plan has.
         Example: 10.
    max_range_days (int): Maximum length, in days, of the time range of a backtest on one of your own datasets.
        Example: 7.
    max_sweep_cartesian (int): Largest full grid, in parameter combinations, a sweep may run with the `grid`
        sampler.
        A grid with more combinations is refused with `400`; the `random` and `lhs` samplers run
        only their `samples` and are not held to it.
         Example: 100.
    max_import_range_hours (int): Maximum length, in hours, of the time range of one dataset import from an
        exchange. Example: 6.
    max_datasets (int): Maximum number of active datasets your tier allows. Example: 3.
    max_dataset_bytes (int): Maximum size, in bytes, of a single dataset version as stored, that is the `bytes` of
        its ready version. For a CSV upload that is the converted file, not the file you upload, so estimate from the
        number of rows. The Datasets guide has the details. Example: 52428800.
    max_total_storage_bytes (int): Maximum combined storage, in bytes, across every dataset, strategy-execution
        signal,
        and registered strategy on your account — one shared pool, not a separate cap per
        resource type, since they all compete for the same underlying storage. See `GET
        /account/usage`'s `storageBytesUsed` for your current usage against this number.
         Example: 104857600.
    field_links (AccountLinks): HAL `_links` for `GET /account`
Account( user_id: str, tier: str, max_execute: int, max_range_days: int, max_sweep_cartesian: int, max_import_range_hours: int, max_datasets: int, max_dataset_bytes: int, max_total_storage_bytes: int, field_links: AccountLinks)
33def __init__(self, user_id, tier, max_execute, max_range_days, max_sweep_cartesian, max_import_range_hours, max_datasets, max_dataset_bytes, max_total_storage_bytes, field_links):
34    self.user_id = user_id
35    self.tier = tier
36    self.max_execute = max_execute
37    self.max_range_days = max_range_days
38    self.max_sweep_cartesian = max_sweep_cartesian
39    self.max_import_range_hours = max_import_range_hours
40    self.max_datasets = max_datasets
41    self.max_dataset_bytes = max_dataset_bytes
42    self.max_total_storage_bytes = max_total_storage_bytes
43    self.field_links = field_links
44    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class Account.

user_id: str
tier: str
max_execute: int
max_range_days: int
max_sweep_cartesian: int
max_import_range_hours: int
max_datasets: int
max_dataset_bytes: int
max_total_storage_bytes: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 65    def to_dict(self) -> dict[str, Any]:
 66        user_id = self.user_id
 67
 68        tier = self.tier
 69
 70        max_execute = self.max_execute
 71
 72        max_range_days = self.max_range_days
 73
 74        max_sweep_cartesian = self.max_sweep_cartesian
 75
 76        max_import_range_hours = self.max_import_range_hours
 77
 78        max_datasets = self.max_datasets
 79
 80        max_dataset_bytes = self.max_dataset_bytes
 81
 82        max_total_storage_bytes = self.max_total_storage_bytes
 83
 84        field_links = self.field_links.to_dict()
 85
 86        field_dict: dict[str, Any] = {}
 87        field_dict.update(self.additional_properties)
 88        field_dict.update(
 89            {
 90                "userId": user_id,
 91                "tier": tier,
 92                "maxExecute": max_execute,
 93                "maxRangeDays": max_range_days,
 94                "maxSweepCartesian": max_sweep_cartesian,
 95                "maxImportRangeHours": max_import_range_hours,
 96                "maxDatasets": max_datasets,
 97                "maxDatasetBytes": max_dataset_bytes,
 98                "maxTotalStorageBytes": max_total_storage_bytes,
 99                "_links": field_links,
100            }
101        )
102
103        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
105    @classmethod
106    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
107        from ..models.account_links import AccountLinks
108
109        d = dict(src_dict)
110        user_id = d.pop("userId")
111
112        tier = d.pop("tier")
113
114        max_execute = d.pop("maxExecute")
115
116        max_range_days = d.pop("maxRangeDays")
117
118        max_sweep_cartesian = d.pop("maxSweepCartesian")
119
120        max_import_range_hours = d.pop("maxImportRangeHours")
121
122        max_datasets = d.pop("maxDatasets")
123
124        max_dataset_bytes = d.pop("maxDatasetBytes")
125
126        max_total_storage_bytes = d.pop("maxTotalStorageBytes")
127
128        field_links = AccountLinks.from_dict(d.pop("_links"))
129
130        account = cls(
131            user_id=user_id,
132            tier=tier,
133            max_execute=max_execute,
134            max_range_days=max_range_days,
135            max_sweep_cartesian=max_sweep_cartesian,
136            max_import_range_hours=max_import_range_hours,
137            max_datasets=max_datasets,
138            max_dataset_bytes=max_dataset_bytes,
139            max_total_storage_bytes=max_total_storage_bytes,
140            field_links=field_links,
141        )
142
143        account.additional_properties = d
144        return account
additional_keys: list[str]
146    @property
147    def additional_keys(self) -> list[str]:
148        return list(self.additional_properties.keys())
class AccountUsage:
 17@_attrs_define
 18class AccountUsage:
 19    """Your live usage of the shared storage pool `GET /account`'s `maxTotalStorageBytes` caps.
 20    Not guaranteed real-time — a just-completed upload or strategy execution may take a short
 21    moment to be reflected here.
 22
 23        Attributes:
 24            datasets_used (int): Active datasets counted — the same set `GET /account`'s `maxDatasets` limits. Example: 2.
 25            dataset_bytes_used (int): Combined bytes of every active dataset's current version. Example: 15728640.
 26            signals_used (int): Recorded strategy-execution signal uploads. Example: 1.
 27            signal_bytes_used (int): Combined bytes of every recorded signal upload. Example: 524288.
 28            strategies_used (int): Registered strategies (see `GET /strategies`). Example: 4.
 29            strategy_bytes_used (int): Combined bytes of each registered strategy's source plus its latest compiled
 30                bytecode. Superseded (non-latest) compilations aren't counted.
 31                 Example: 40960.
 32            storage_bytes_used (int): `datasetBytesUsed + signalBytesUsed + strategyBytesUsed` — the number checked
 33                against `GET /account`'s `maxTotalStorageBytes`.
 34                 Example: 16293888.
 35            field_links (AccountUsageLinks): HAL `_links` for `GET /account/usage`
 36    """
 37
 38    datasets_used: int
 39    dataset_bytes_used: int
 40    signals_used: int
 41    signal_bytes_used: int
 42    strategies_used: int
 43    strategy_bytes_used: int
 44    storage_bytes_used: int
 45    field_links: AccountUsageLinks
 46    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 47
 48    def to_dict(self) -> dict[str, Any]:
 49        datasets_used = self.datasets_used
 50
 51        dataset_bytes_used = self.dataset_bytes_used
 52
 53        signals_used = self.signals_used
 54
 55        signal_bytes_used = self.signal_bytes_used
 56
 57        strategies_used = self.strategies_used
 58
 59        strategy_bytes_used = self.strategy_bytes_used
 60
 61        storage_bytes_used = self.storage_bytes_used
 62
 63        field_links = self.field_links.to_dict()
 64
 65        field_dict: dict[str, Any] = {}
 66        field_dict.update(self.additional_properties)
 67        field_dict.update(
 68            {
 69                "datasetsUsed": datasets_used,
 70                "datasetBytesUsed": dataset_bytes_used,
 71                "signalsUsed": signals_used,
 72                "signalBytesUsed": signal_bytes_used,
 73                "strategiesUsed": strategies_used,
 74                "strategyBytesUsed": strategy_bytes_used,
 75                "storageBytesUsed": storage_bytes_used,
 76                "_links": field_links,
 77            }
 78        )
 79
 80        return field_dict
 81
 82    @classmethod
 83    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 84        from ..models.account_usage_links import AccountUsageLinks
 85
 86        d = dict(src_dict)
 87        datasets_used = d.pop("datasetsUsed")
 88
 89        dataset_bytes_used = d.pop("datasetBytesUsed")
 90
 91        signals_used = d.pop("signalsUsed")
 92
 93        signal_bytes_used = d.pop("signalBytesUsed")
 94
 95        strategies_used = d.pop("strategiesUsed")
 96
 97        strategy_bytes_used = d.pop("strategyBytesUsed")
 98
 99        storage_bytes_used = d.pop("storageBytesUsed")
100
101        field_links = AccountUsageLinks.from_dict(d.pop("_links"))
102
103        account_usage = cls(
104            datasets_used=datasets_used,
105            dataset_bytes_used=dataset_bytes_used,
106            signals_used=signals_used,
107            signal_bytes_used=signal_bytes_used,
108            strategies_used=strategies_used,
109            strategy_bytes_used=strategy_bytes_used,
110            storage_bytes_used=storage_bytes_used,
111            field_links=field_links,
112        )
113
114        account_usage.additional_properties = d
115        return account_usage
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

Your live usage of the shared storage pool GET /account's maxTotalStorageBytes caps. Not guaranteed real-time — a just-completed upload or strategy execution may take a short moment to be reflected here.

Attributes:
    datasets_used (int): Active datasets counted — the same set `GET /account`'s `maxDatasets` limits. Example: 2.
    dataset_bytes_used (int): Combined bytes of every active dataset's current version. Example: 15728640.
    signals_used (int): Recorded strategy-execution signal uploads. Example: 1.
    signal_bytes_used (int): Combined bytes of every recorded signal upload. Example: 524288.
    strategies_used (int): Registered strategies (see `GET /strategies`). Example: 4.
    strategy_bytes_used (int): Combined bytes of each registered strategy's source plus its latest compiled
        bytecode. Superseded (non-latest) compilations aren't counted.
         Example: 40960.
    storage_bytes_used (int): `datasetBytesUsed + signalBytesUsed + strategyBytesUsed` — the number checked
        against `GET /account`'s `maxTotalStorageBytes`.
         Example: 16293888.
    field_links (AccountUsageLinks): HAL `_links` for `GET /account/usage`
AccountUsage( datasets_used: int, dataset_bytes_used: int, signals_used: int, signal_bytes_used: int, strategies_used: int, strategy_bytes_used: int, storage_bytes_used: int, field_links: AccountUsageLinks)
31def __init__(self, datasets_used, dataset_bytes_used, signals_used, signal_bytes_used, strategies_used, strategy_bytes_used, storage_bytes_used, field_links):
32    self.datasets_used = datasets_used
33    self.dataset_bytes_used = dataset_bytes_used
34    self.signals_used = signals_used
35    self.signal_bytes_used = signal_bytes_used
36    self.strategies_used = strategies_used
37    self.strategy_bytes_used = strategy_bytes_used
38    self.storage_bytes_used = storage_bytes_used
39    self.field_links = field_links
40    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class AccountUsage.

datasets_used: int
dataset_bytes_used: int
signals_used: int
signal_bytes_used: int
strategies_used: int
strategy_bytes_used: int
storage_bytes_used: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
48    def to_dict(self) -> dict[str, Any]:
49        datasets_used = self.datasets_used
50
51        dataset_bytes_used = self.dataset_bytes_used
52
53        signals_used = self.signals_used
54
55        signal_bytes_used = self.signal_bytes_used
56
57        strategies_used = self.strategies_used
58
59        strategy_bytes_used = self.strategy_bytes_used
60
61        storage_bytes_used = self.storage_bytes_used
62
63        field_links = self.field_links.to_dict()
64
65        field_dict: dict[str, Any] = {}
66        field_dict.update(self.additional_properties)
67        field_dict.update(
68            {
69                "datasetsUsed": datasets_used,
70                "datasetBytesUsed": dataset_bytes_used,
71                "signalsUsed": signals_used,
72                "signalBytesUsed": signal_bytes_used,
73                "strategiesUsed": strategies_used,
74                "strategyBytesUsed": strategy_bytes_used,
75                "storageBytesUsed": storage_bytes_used,
76                "_links": field_links,
77            }
78        )
79
80        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 82    @classmethod
 83    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 84        from ..models.account_usage_links import AccountUsageLinks
 85
 86        d = dict(src_dict)
 87        datasets_used = d.pop("datasetsUsed")
 88
 89        dataset_bytes_used = d.pop("datasetBytesUsed")
 90
 91        signals_used = d.pop("signalsUsed")
 92
 93        signal_bytes_used = d.pop("signalBytesUsed")
 94
 95        strategies_used = d.pop("strategiesUsed")
 96
 97        strategy_bytes_used = d.pop("strategyBytesUsed")
 98
 99        storage_bytes_used = d.pop("storageBytesUsed")
100
101        field_links = AccountUsageLinks.from_dict(d.pop("_links"))
102
103        account_usage = cls(
104            datasets_used=datasets_used,
105            dataset_bytes_used=dataset_bytes_used,
106            signals_used=signals_used,
107            signal_bytes_used=signal_bytes_used,
108            strategies_used=strategies_used,
109            strategy_bytes_used=strategy_bytes_used,
110            storage_bytes_used=storage_bytes_used,
111            field_links=field_links,
112        )
113
114        account_usage.additional_properties = d
115        return account_usage
additional_keys: list[str]
117    @property
118    def additional_keys(self) -> list[str]:
119        return list(self.additional_properties.keys())
class AuthTokenError:
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.

AuthTokenError( code: AuthTokenErrorCode, message: str)
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.

message: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
59    @property
60    def additional_keys(self) -> list[str]:
61        return list(self.additional_properties.keys())
class AuthTokenErrorCode(builtins.str, enum.Enum):
 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'.

APIKEY_EXPIRED = <AuthTokenErrorCode.APIKEY_EXPIRED: 'apikey_expired'>
APIKEY_REVOKED = <AuthTokenErrorCode.APIKEY_REVOKED: 'apikey_revoked'>
INVALID_APIKEY = <AuthTokenErrorCode.INVALID_APIKEY: 'invalid_apikey'>
class AuthTokenResponse:
 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.

AuthTokenResponse( access_token: str, token_type: AuthTokenResponseTokenType, expires_in: int, tier: AuthTokenResponseTier, scopes: list[str] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

access_token: str
expires_in: int
scopes: list[str] | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
88    @property
89    def additional_keys(self) -> list[str]:
90        return list(self.additional_properties.keys())
class AuthTokenResponseTier(builtins.str, enum.Enum):
 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'.

BASIC = <AuthTokenResponseTier.BASIC: 'basic'>
ELITE = <AuthTokenResponseTier.ELITE: 'elite'>
FREE = <AuthTokenResponseTier.FREE: 'free'>
PRO = <AuthTokenResponseTier.PRO: 'pro'>
class AuthTokenResponseTokenType(builtins.str, enum.Enum):
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'.

BEARER = <AuthTokenResponseTokenType.BEARER: 'Bearer'>
class BacktestJobResult:
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

BacktestJobResult( results: ResultMap, state: JobState)
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.

results: ResultMap
state: JobState
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
68    @property
69    def additional_keys(self) -> list[str]:
70        return list(self.additional_properties.keys())
class CancelBacktestResponse200:
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.

CancelBacktestResponse200( status: CancelBacktestResponse200Status | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, job_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

status: CancelBacktestResponse200Status | qtsurfer.api.client._generated.types.Unset
job_id: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
65    @property
66    def additional_keys(self) -> list[str]:
67        return list(self.additional_properties.keys())
class CancelBacktestResponse200Status(builtins.str, enum.Enum):
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'.

CANCELLING = <CancelBacktestResponse200Status.CANCELLING: 'cancelling'>
class CancelSweepResponse200:
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):

CancelSweepResponse200( 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.

sweep_id: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
58    @property
59    def additional_keys(self) -> list[str]:
60        return list(self.additional_properties.keys())
class CancelSweepResponse200Status(builtins.str, enum.Enum):
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'.

CANCELLING = <CancelSweepResponse200Status.CANCELLING: 'cancelling'>
class CompileStrategyResponse200:
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. How much formatting the id ignores depends on
25            the language — see `POST /strategy` for exactly which rewrites preserve it and which do
26            not.
27             Example: 6bsh31ikwkuivhtgcoa6s4.
28        declared_properties (list[DeclaredProperty] | Unset): What could be established about this strategy's sweep-key
29            vocabulary without
30            constructing it. See `DeclaredProperty` — best-effort, not exhaustive.
31    """
32
33    strategy_id: str
34    declared_properties: list[DeclaredProperty] | Unset = UNSET
35    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
36
37    def to_dict(self) -> dict[str, Any]:
38        strategy_id = self.strategy_id
39
40        declared_properties: list[dict[str, Any]] | Unset = UNSET
41        if not isinstance(self.declared_properties, Unset):
42            declared_properties = []
43            for declared_properties_item_data in self.declared_properties:
44                declared_properties_item = declared_properties_item_data.to_dict()
45                declared_properties.append(declared_properties_item)
46
47        field_dict: dict[str, Any] = {}
48        field_dict.update(self.additional_properties)
49        field_dict.update(
50            {
51                "strategyId": strategy_id,
52            }
53        )
54        if declared_properties is not UNSET:
55            field_dict["declaredProperties"] = declared_properties
56
57        return field_dict
58
59    @classmethod
60    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
61        from ..models.declared_property import DeclaredProperty
62
63        d = dict(src_dict)
64        strategy_id = d.pop("strategyId")
65
66        _declared_properties = d.pop("declaredProperties", UNSET)
67        declared_properties: list[DeclaredProperty] | Unset = UNSET
68        if _declared_properties is not UNSET:
69            declared_properties = []
70            for declared_properties_item_data in _declared_properties:
71                declared_properties_item = DeclaredProperty.from_dict(declared_properties_item_data)
72
73                declared_properties.append(declared_properties_item)
74
75        compile_strategy_response_200 = cls(
76            strategy_id=strategy_id,
77            declared_properties=declared_properties,
78        )
79
80        compile_strategy_response_200.additional_properties = d
81        return compile_strategy_response_200
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

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. How much formatting the id ignores depends on the language — 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.

CompileStrategyResponse200( strategy_id: str, declared_properties: list[DeclaredProperty] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

strategy_id: str
declared_properties: list[DeclaredProperty] | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
37    def to_dict(self) -> dict[str, Any]:
38        strategy_id = self.strategy_id
39
40        declared_properties: list[dict[str, Any]] | Unset = UNSET
41        if not isinstance(self.declared_properties, Unset):
42            declared_properties = []
43            for declared_properties_item_data in self.declared_properties:
44                declared_properties_item = declared_properties_item_data.to_dict()
45                declared_properties.append(declared_properties_item)
46
47        field_dict: dict[str, Any] = {}
48        field_dict.update(self.additional_properties)
49        field_dict.update(
50            {
51                "strategyId": strategy_id,
52            }
53        )
54        if declared_properties is not UNSET:
55            field_dict["declaredProperties"] = declared_properties
56
57        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
59    @classmethod
60    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
61        from ..models.declared_property import DeclaredProperty
62
63        d = dict(src_dict)
64        strategy_id = d.pop("strategyId")
65
66        _declared_properties = d.pop("declaredProperties", UNSET)
67        declared_properties: list[DeclaredProperty] | Unset = UNSET
68        if _declared_properties is not UNSET:
69            declared_properties = []
70            for declared_properties_item_data in _declared_properties:
71                declared_properties_item = DeclaredProperty.from_dict(declared_properties_item_data)
72
73                declared_properties.append(declared_properties_item)
74
75        compile_strategy_response_200 = cls(
76            strategy_id=strategy_id,
77            declared_properties=declared_properties,
78        )
79
80        compile_strategy_response_200.additional_properties = d
81        return compile_strategy_response_200
additional_keys: list[str]
83    @property
84    def additional_keys(self) -> list[str]:
85        return list(self.additional_properties.keys())
class CoverageWindow:
 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.

CoverageWindow( from_: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, to: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, inactive_since: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

from_: datetime.datetime | qtsurfer.api.client._generated.types.Unset
to: datetime.datetime | qtsurfer.api.client._generated.types.Unset
inactive_since: datetime.datetime | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
92    @property
93    def additional_keys(self) -> list[str]:
94        return list(self.additional_properties.keys())
class CreateDatasetBody:
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.

CreateDatasetBody(name: str, instrument: str)
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.

name: str
instrument: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
56    @property
57    def additional_keys(self) -> list[str]:
58        return list(self.additional_properties.keys())
class Dataset:
 20@_attrs_define
 21class Dataset:
 22    """A dataset's own metadata — not its data. `currentVersionId` is what a prepare against
 23    `exchangeId: user` reads by default; see `DatasetVersion` for what a version carries.
 24
 25    `from`/`to`/`cadence`/`timestampUnit`/`bytes`/`rows`/`gaps`/`largestGapSteps` mirror that
 26    current version's own discovered range, cadence, timestamp unit and metrics, so you don't
 27    need a second call to `GET /datasets/{datasetId}/uploads/{uploadId}` just to see what a
 28    dataset covers.
 29
 30        Attributes:
 31            dataset_id (str): Opaque id, returned by `POST /datasets`. Example: ds_3f9a1c2e7b0d4a5f.
 32            name (str): Unique among your datasets. Example: My BTC ticks.
 33            type_ (DatasetType): `ticker` for an upload or a `dex` import with no `cadence` requested (native per-trade
 34                data). `klines` for a `dex` import that requested a candle `cadence` — pre-aggregated
 35                bars rather than raw ticks. Purely informational; both shapes are read the same way.
 36                 Example: ticker.
 37            instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
 38            created_at (datetime.datetime): When the dataset was created. Example: 2026-08-20T09:00:00Z.
 39            status (DatasetStatus): * `ready` — `currentVersionId` is set; `from`/`to`/`cadence`/`bytes`/`rows`/`gaps`/
 40                  `largestGapSteps` describe it.
 41                * `failed` — the most recent upload/import attempt failed. `currentVersionId` and the
 42                  fields above are absent — there is nothing to read yet. See `error`.
 43                * `pending` — nothing has ever been attempted (just created, or an upload was never
 44                  finalized).
 45                 Example: ready.
 46            current_version_id (str | Unset): The id of the most recently finalized, successfully ingested version. Absent
 47                until at
 48                least one upload has finished ingesting.
 49                 Example: dsv_8e2b4f19c6a03d7e.
 50            deleted_at (datetime.datetime | Unset): When you deleted this dataset. Only ever present in `GET
 51                /datasets?includeDeleted=true`,
 52                and only on datasets you have deleted.
 53            updated_at (datetime.datetime | Unset): When `currentVersionId` last changed. Absent until it has a value.
 54                Example: 2026-08-20T09:04:12Z.
 55            from_ (datetime.datetime | Unset): Start of `currentVersionId`'s own data range, as discovered at ingest time.
 56                Absent
 57                until a version exists.
 58                 Example: 2026-03-01T00:00:00Z.
 59            to (datetime.datetime | Unset): End of `currentVersionId`'s own data range, as discovered at ingest time. Absent
 60                until
 61                a version exists.
 62                 Example: 2026-03-08T00:00:00Z.
 63            cadence (str | Unset): `currentVersionId`'s own discovered cadence — a fixed grid (e.g. `1s`, `1m`, `1h`) or
 64                `rt` (see `DatasetVersion.cadence`). Absent until a version exists.
 65                 Example: 1m.
 66            timestamp_unit (DatasetTimestampUnit | Unset): `currentVersionId`'s own timestamp unit (see
 67                `DatasetVersion.timestampUnit`) — decode
 68                the `timestamp` column of `dataUrl`'s file accordingly. Present only when `status` is
 69                `ready`.
 70                 Example: iso.
 71            bytes_ (int | Unset): Size of `currentVersionId`'s own stored file. Present only when `status` is `ready` —
 72                see `DatasetVersion.bytes` for what it measures exactly.
 73                 Example: 4831022.
 74            rows (int | Unset): `currentVersionId`'s own row count. Present only when `status` is `ready`. Example: 86400.
 75            gaps (int | Unset): `currentVersionId`'s own gap count at its discovered cadence. Present only when `status` is
 76                `ready`.
 77            largest_gap_steps (int | Unset): `currentVersionId`'s own largest gap, in units of its discovered cadence step.
 78                Present only when `status` is `ready`.
 79            error (str | Unset): A human-readable reason the most recent upload/import attempt failed. Present only
 80                when `status` is `failed`.
 81                 Example: line 3: column 'close' is not a number: not-a-number.
 82    """
 83
 84    dataset_id: str
 85    name: str
 86    type_: DatasetType
 87    instrument: str
 88    created_at: datetime.datetime
 89    status: DatasetStatus
 90    current_version_id: str | Unset = UNSET
 91    deleted_at: datetime.datetime | Unset = UNSET
 92    updated_at: datetime.datetime | Unset = UNSET
 93    from_: datetime.datetime | Unset = UNSET
 94    to: datetime.datetime | Unset = UNSET
 95    cadence: str | Unset = UNSET
 96    timestamp_unit: DatasetTimestampUnit | Unset = UNSET
 97    bytes_: int | Unset = UNSET
 98    rows: int | Unset = UNSET
 99    gaps: int | Unset = UNSET
100    largest_gap_steps: int | Unset = UNSET
101    error: str | Unset = UNSET
102    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
103
104    def to_dict(self) -> dict[str, Any]:
105        dataset_id = self.dataset_id
106
107        name = self.name
108
109        type_ = self.type_.value
110
111        instrument = self.instrument
112
113        created_at = self.created_at.isoformat()
114
115        status = self.status.value
116
117        current_version_id = self.current_version_id
118
119        deleted_at: str | Unset = UNSET
120        if not isinstance(self.deleted_at, Unset):
121            deleted_at = self.deleted_at.isoformat()
122
123        updated_at: str | Unset = UNSET
124        if not isinstance(self.updated_at, Unset):
125            updated_at = self.updated_at.isoformat()
126
127        from_: str | Unset = UNSET
128        if not isinstance(self.from_, Unset):
129            from_ = self.from_.isoformat()
130
131        to: str | Unset = UNSET
132        if not isinstance(self.to, Unset):
133            to = self.to.isoformat()
134
135        cadence = self.cadence
136
137        timestamp_unit: str | Unset = UNSET
138        if not isinstance(self.timestamp_unit, Unset):
139            timestamp_unit = self.timestamp_unit.value
140
141        bytes_ = self.bytes_
142
143        rows = self.rows
144
145        gaps = self.gaps
146
147        largest_gap_steps = self.largest_gap_steps
148
149        error = self.error
150
151        field_dict: dict[str, Any] = {}
152        field_dict.update(self.additional_properties)
153        field_dict.update(
154            {
155                "datasetId": dataset_id,
156                "name": name,
157                "type": type_,
158                "instrument": instrument,
159                "createdAt": created_at,
160                "status": status,
161            }
162        )
163        if current_version_id is not UNSET:
164            field_dict["currentVersionId"] = current_version_id
165        if deleted_at is not UNSET:
166            field_dict["deletedAt"] = deleted_at
167        if updated_at is not UNSET:
168            field_dict["updatedAt"] = updated_at
169        if from_ is not UNSET:
170            field_dict["from"] = from_
171        if to is not UNSET:
172            field_dict["to"] = to
173        if cadence is not UNSET:
174            field_dict["cadence"] = cadence
175        if timestamp_unit is not UNSET:
176            field_dict["timestampUnit"] = timestamp_unit
177        if bytes_ is not UNSET:
178            field_dict["bytes"] = bytes_
179        if rows is not UNSET:
180            field_dict["rows"] = rows
181        if gaps is not UNSET:
182            field_dict["gaps"] = gaps
183        if largest_gap_steps is not UNSET:
184            field_dict["largestGapSteps"] = largest_gap_steps
185        if error is not UNSET:
186            field_dict["error"] = error
187
188        return field_dict
189
190    @classmethod
191    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
192        d = dict(src_dict)
193        dataset_id = d.pop("datasetId")
194
195        name = d.pop("name")
196
197        type_ = DatasetType(d.pop("type"))
198
199        instrument = d.pop("instrument")
200
201        created_at = isoparse(d.pop("createdAt"))
202
203        status = DatasetStatus(d.pop("status"))
204
205        current_version_id = d.pop("currentVersionId", UNSET)
206
207        _deleted_at = d.pop("deletedAt", UNSET)
208        deleted_at: datetime.datetime | Unset
209        if isinstance(_deleted_at, Unset):
210            deleted_at = UNSET
211        else:
212            deleted_at = isoparse(_deleted_at)
213
214        _updated_at = d.pop("updatedAt", UNSET)
215        updated_at: datetime.datetime | Unset
216        if isinstance(_updated_at, Unset):
217            updated_at = UNSET
218        else:
219            updated_at = isoparse(_updated_at)
220
221        _from_ = d.pop("from", UNSET)
222        from_: datetime.datetime | Unset
223        if isinstance(_from_, Unset):
224            from_ = UNSET
225        else:
226            from_ = isoparse(_from_)
227
228        _to = d.pop("to", UNSET)
229        to: datetime.datetime | Unset
230        if isinstance(_to, Unset):
231            to = UNSET
232        else:
233            to = isoparse(_to)
234
235        cadence = d.pop("cadence", UNSET)
236
237        _timestamp_unit = d.pop("timestampUnit", UNSET)
238        timestamp_unit: DatasetTimestampUnit | Unset
239        if isinstance(_timestamp_unit, Unset):
240            timestamp_unit = UNSET
241        else:
242            timestamp_unit = DatasetTimestampUnit(_timestamp_unit)
243
244        bytes_ = d.pop("bytes", UNSET)
245
246        rows = d.pop("rows", UNSET)
247
248        gaps = d.pop("gaps", UNSET)
249
250        largest_gap_steps = d.pop("largestGapSteps", UNSET)
251
252        error = d.pop("error", UNSET)
253
254        dataset = cls(
255            dataset_id=dataset_id,
256            name=name,
257            type_=type_,
258            instrument=instrument,
259            created_at=created_at,
260            status=status,
261            current_version_id=current_version_id,
262            deleted_at=deleted_at,
263            updated_at=updated_at,
264            from_=from_,
265            to=to,
266            cadence=cadence,
267            timestamp_unit=timestamp_unit,
268            bytes_=bytes_,
269            rows=rows,
270            gaps=gaps,
271            largest_gap_steps=largest_gap_steps,
272            error=error,
273        )
274
275        dataset.additional_properties = d
276        return dataset
277
278    @property
279    def additional_keys(self) -> list[str]:
280        return list(self.additional_properties.keys())
281
282    def __getitem__(self, key: str) -> Any:
283        return self.additional_properties[key]
284
285    def __setitem__(self, key: str, value: Any) -> None:
286        self.additional_properties[key] = value
287
288    def __delitem__(self, key: str) -> None:
289        del self.additional_properties[key]
290
291    def __contains__(self, key: str) -> bool:
292        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/timestampUnit/bytes/rows/gaps/largestGapSteps mirror that current version's own discovered range, cadence, timestamp unit and metrics, so you don't need a second call to GET /datasets/{datasetId}/uploads/{uploadId} just to see what a dataset covers.

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): `ticker` for an upload or a `dex` import with no `cadence` requested (native per-trade
        data). `klines` for a `dex` import that requested a candle `cadence` — pre-aggregated
        bars rather than raw ticks. Purely informational; both shapes are read the same way.
         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.
    status (DatasetStatus): * `ready` — `currentVersionId` is set; `from`/`to`/`cadence`/`bytes`/`rows`/`gaps`/
          `largestGapSteps` describe it.
        * `failed` — the most recent upload/import attempt failed. `currentVersionId` and the
          fields above are absent — there is nothing to read yet. See `error`.
        * `pending` — nothing has ever been attempted (just created, or an upload was never
          finalized).
         Example: ready.
    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.
    deleted_at (datetime.datetime | Unset): When you deleted this dataset. Only ever present in `GET
        /datasets?includeDeleted=true`,
        and only on datasets you have deleted.
    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 cadence — a fixed grid (e.g. `1s`, `1m`, `1h`) or
        `rt` (see `DatasetVersion.cadence`). Absent until a version exists.
         Example: 1m.
    timestamp_unit (DatasetTimestampUnit | Unset): `currentVersionId`'s own timestamp unit (see
        `DatasetVersion.timestampUnit`) — decode
        the `timestamp` column of `dataUrl`'s file accordingly. Present only when `status` is
        `ready`.
         Example: iso.
    bytes_ (int | Unset): Size of `currentVersionId`'s own stored file. Present only when `status` is `ready` —
        see `DatasetVersion.bytes` for what it measures exactly.
         Example: 4831022.
    rows (int | Unset): `currentVersionId`'s own row count. Present only when `status` is `ready`. Example: 86400.
    gaps (int | Unset): `currentVersionId`'s own gap count at its discovered cadence. Present only when `status` is
        `ready`.
    largest_gap_steps (int | Unset): `currentVersionId`'s own largest gap, in units of its discovered cadence step.
        Present only when `status` is `ready`.
    error (str | Unset): A human-readable reason the most recent upload/import attempt failed. Present only
        when `status` is `failed`.
         Example: line 3: column 'close' is not a number: not-a-number.
Dataset( dataset_id: str, name: str, type_: DatasetType, instrument: str, created_at: datetime.datetime, status: DatasetStatus, current_version_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, deleted_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, updated_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, from_: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, to: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cadence: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, timestamp_unit: DatasetTimestampUnit | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, bytes_: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, rows: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, gaps: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, largest_gap_steps: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, error: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
41def __init__(self, dataset_id, name, type_, instrument, created_at, status, current_version_id=attr_dict['current_version_id'].default, deleted_at=attr_dict['deleted_at'].default, updated_at=attr_dict['updated_at'].default, from_=attr_dict['from_'].default, to=attr_dict['to'].default, cadence=attr_dict['cadence'].default, timestamp_unit=attr_dict['timestamp_unit'].default, bytes_=attr_dict['bytes_'].default, rows=attr_dict['rows'].default, gaps=attr_dict['gaps'].default, largest_gap_steps=attr_dict['largest_gap_steps'].default, error=attr_dict['error'].default):
42    self.dataset_id = dataset_id
43    self.name = name
44    self.type_ = type_
45    self.instrument = instrument
46    self.created_at = created_at
47    self.status = status
48    self.current_version_id = current_version_id
49    self.deleted_at = deleted_at
50    self.updated_at = updated_at
51    self.from_ = from_
52    self.to = to
53    self.cadence = cadence
54    self.timestamp_unit = timestamp_unit
55    self.bytes_ = bytes_
56    self.rows = rows
57    self.gaps = gaps
58    self.largest_gap_steps = largest_gap_steps
59    self.error = error
60    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class Dataset.

dataset_id: str
name: str
type_: DatasetType
instrument: str
created_at: datetime.datetime
status: DatasetStatus
current_version_id: str | qtsurfer.api.client._generated.types.Unset
deleted_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
updated_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
from_: datetime.datetime | qtsurfer.api.client._generated.types.Unset
to: datetime.datetime | qtsurfer.api.client._generated.types.Unset
cadence: str | qtsurfer.api.client._generated.types.Unset
timestamp_unit: DatasetTimestampUnit | qtsurfer.api.client._generated.types.Unset
bytes_: int | qtsurfer.api.client._generated.types.Unset
rows: int | qtsurfer.api.client._generated.types.Unset
gaps: int | qtsurfer.api.client._generated.types.Unset
largest_gap_steps: int | qtsurfer.api.client._generated.types.Unset
error: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
104    def to_dict(self) -> dict[str, Any]:
105        dataset_id = self.dataset_id
106
107        name = self.name
108
109        type_ = self.type_.value
110
111        instrument = self.instrument
112
113        created_at = self.created_at.isoformat()
114
115        status = self.status.value
116
117        current_version_id = self.current_version_id
118
119        deleted_at: str | Unset = UNSET
120        if not isinstance(self.deleted_at, Unset):
121            deleted_at = self.deleted_at.isoformat()
122
123        updated_at: str | Unset = UNSET
124        if not isinstance(self.updated_at, Unset):
125            updated_at = self.updated_at.isoformat()
126
127        from_: str | Unset = UNSET
128        if not isinstance(self.from_, Unset):
129            from_ = self.from_.isoformat()
130
131        to: str | Unset = UNSET
132        if not isinstance(self.to, Unset):
133            to = self.to.isoformat()
134
135        cadence = self.cadence
136
137        timestamp_unit: str | Unset = UNSET
138        if not isinstance(self.timestamp_unit, Unset):
139            timestamp_unit = self.timestamp_unit.value
140
141        bytes_ = self.bytes_
142
143        rows = self.rows
144
145        gaps = self.gaps
146
147        largest_gap_steps = self.largest_gap_steps
148
149        error = self.error
150
151        field_dict: dict[str, Any] = {}
152        field_dict.update(self.additional_properties)
153        field_dict.update(
154            {
155                "datasetId": dataset_id,
156                "name": name,
157                "type": type_,
158                "instrument": instrument,
159                "createdAt": created_at,
160                "status": status,
161            }
162        )
163        if current_version_id is not UNSET:
164            field_dict["currentVersionId"] = current_version_id
165        if deleted_at is not UNSET:
166            field_dict["deletedAt"] = deleted_at
167        if updated_at is not UNSET:
168            field_dict["updatedAt"] = updated_at
169        if from_ is not UNSET:
170            field_dict["from"] = from_
171        if to is not UNSET:
172            field_dict["to"] = to
173        if cadence is not UNSET:
174            field_dict["cadence"] = cadence
175        if timestamp_unit is not UNSET:
176            field_dict["timestampUnit"] = timestamp_unit
177        if bytes_ is not UNSET:
178            field_dict["bytes"] = bytes_
179        if rows is not UNSET:
180            field_dict["rows"] = rows
181        if gaps is not UNSET:
182            field_dict["gaps"] = gaps
183        if largest_gap_steps is not UNSET:
184            field_dict["largestGapSteps"] = largest_gap_steps
185        if error is not UNSET:
186            field_dict["error"] = error
187
188        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
190    @classmethod
191    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
192        d = dict(src_dict)
193        dataset_id = d.pop("datasetId")
194
195        name = d.pop("name")
196
197        type_ = DatasetType(d.pop("type"))
198
199        instrument = d.pop("instrument")
200
201        created_at = isoparse(d.pop("createdAt"))
202
203        status = DatasetStatus(d.pop("status"))
204
205        current_version_id = d.pop("currentVersionId", UNSET)
206
207        _deleted_at = d.pop("deletedAt", UNSET)
208        deleted_at: datetime.datetime | Unset
209        if isinstance(_deleted_at, Unset):
210            deleted_at = UNSET
211        else:
212            deleted_at = isoparse(_deleted_at)
213
214        _updated_at = d.pop("updatedAt", UNSET)
215        updated_at: datetime.datetime | Unset
216        if isinstance(_updated_at, Unset):
217            updated_at = UNSET
218        else:
219            updated_at = isoparse(_updated_at)
220
221        _from_ = d.pop("from", UNSET)
222        from_: datetime.datetime | Unset
223        if isinstance(_from_, Unset):
224            from_ = UNSET
225        else:
226            from_ = isoparse(_from_)
227
228        _to = d.pop("to", UNSET)
229        to: datetime.datetime | Unset
230        if isinstance(_to, Unset):
231            to = UNSET
232        else:
233            to = isoparse(_to)
234
235        cadence = d.pop("cadence", UNSET)
236
237        _timestamp_unit = d.pop("timestampUnit", UNSET)
238        timestamp_unit: DatasetTimestampUnit | Unset
239        if isinstance(_timestamp_unit, Unset):
240            timestamp_unit = UNSET
241        else:
242            timestamp_unit = DatasetTimestampUnit(_timestamp_unit)
243
244        bytes_ = d.pop("bytes", UNSET)
245
246        rows = d.pop("rows", UNSET)
247
248        gaps = d.pop("gaps", UNSET)
249
250        largest_gap_steps = d.pop("largestGapSteps", UNSET)
251
252        error = d.pop("error", UNSET)
253
254        dataset = cls(
255            dataset_id=dataset_id,
256            name=name,
257            type_=type_,
258            instrument=instrument,
259            created_at=created_at,
260            status=status,
261            current_version_id=current_version_id,
262            deleted_at=deleted_at,
263            updated_at=updated_at,
264            from_=from_,
265            to=to,
266            cadence=cadence,
267            timestamp_unit=timestamp_unit,
268            bytes_=bytes_,
269            rows=rows,
270            gaps=gaps,
271            largest_gap_steps=largest_gap_steps,
272            error=error,
273        )
274
275        dataset.additional_properties = d
276        return dataset
additional_keys: list[str]
278    @property
279    def additional_keys(self) -> list[str]:
280        return list(self.additional_properties.keys())
class DatasetCreated:
 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.
DatasetCreated( upload_id: str, upload: DatasetUploadTarget, dataset_id: str, name: str, type_: DatasetCreatedType, instrument: str)
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.

upload_id: str
dataset_id: str
name: str
instrument: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
102    @property
103    def additional_keys(self) -> list[str]:
104        return list(self.additional_properties.keys())
class DatasetCreatedType(builtins.str, enum.Enum):
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'.

TICKER = <DatasetCreatedType.TICKER: 'ticker'>
class DatasetImportCreated:
15@_attrs_define
16class DatasetImportCreated:
17    """The response to `POST /datasets/imports` — the dataset now exists, and its fetch has started.
18
19    Attributes:
20        dataset_id (str): Opaque id of the newly created dataset — same id space as `POST /datasets`. Example:
21            ds_3f9a1c2e7b0d4a5f.
22        import_id (str): Identifies this import. Pass to `GET /datasets/{datasetId}/imports/{importId}` to poll
23            it — there is no separate "finalize" step the way an upload has.
24             Example: imp_01j9z1x2y3z4a5b6c7d8e9f0g1.
25        job_id (str): The fetch/ingest job id. Example: dataset-
26            import:00000000-.../ds_3f9a1c2e7b0d4a5f:imp_01j9z1x2y3z4a5b6c7d8e9f0g1.
27        status (DatasetImportCreatedStatus): Always `fetching` in this response — the fetch has only just started.
28            Example: fetching.
29    """
30
31    dataset_id: str
32    import_id: str
33    job_id: str
34    status: DatasetImportCreatedStatus
35    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
36
37    def to_dict(self) -> dict[str, Any]:
38        dataset_id = self.dataset_id
39
40        import_id = self.import_id
41
42        job_id = self.job_id
43
44        status = self.status.value
45
46        field_dict: dict[str, Any] = {}
47        field_dict.update(self.additional_properties)
48        field_dict.update(
49            {
50                "datasetId": dataset_id,
51                "importId": import_id,
52                "jobId": job_id,
53                "status": status,
54            }
55        )
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        dataset_id = d.pop("datasetId")
63
64        import_id = d.pop("importId")
65
66        job_id = d.pop("jobId")
67
68        status = DatasetImportCreatedStatus(d.pop("status"))
69
70        dataset_import_created = cls(
71            dataset_id=dataset_id,
72            import_id=import_id,
73            job_id=job_id,
74            status=status,
75        )
76
77        dataset_import_created.additional_properties = d
78        return dataset_import_created
79
80    @property
81    def additional_keys(self) -> list[str]:
82        return list(self.additional_properties.keys())
83
84    def __getitem__(self, key: str) -> Any:
85        return self.additional_properties[key]
86
87    def __setitem__(self, key: str, value: Any) -> None:
88        self.additional_properties[key] = value
89
90    def __delitem__(self, key: str) -> None:
91        del self.additional_properties[key]
92
93    def __contains__(self, key: str) -> bool:
94        return key in self.additional_properties

The response to POST /datasets/imports — the dataset now exists, and its fetch has started.

Attributes: dataset_id (str): Opaque id of the newly created dataset — same id space as POST /datasets. Example: ds_3f9a1c2e7b0d4a5f. import_id (str): Identifies this import. Pass to GET /datasets/{datasetId}/imports/{importId} to poll it — there is no separate "finalize" step the way an upload has. Example: imp_01j9z1x2y3z4a5b6c7d8e9f0g1. job_id (str): The fetch/ingest job id. Example: dataset- import:00000000-.../ds_3f9a1c2e7b0d4a5f:imp_01j9z1x2y3z4a5b6c7d8e9f0g1. status (DatasetImportCreatedStatus): Always fetching in this response — the fetch has only just started. Example: fetching.

DatasetImportCreated( dataset_id: str, import_id: str, job_id: str, status: DatasetImportCreatedStatus)
27def __init__(self, dataset_id, import_id, job_id, status):
28    self.dataset_id = dataset_id
29    self.import_id = import_id
30    self.job_id = job_id
31    self.status = status
32    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class DatasetImportCreated.

dataset_id: str
import_id: str
job_id: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
37    def to_dict(self) -> dict[str, Any]:
38        dataset_id = self.dataset_id
39
40        import_id = self.import_id
41
42        job_id = self.job_id
43
44        status = self.status.value
45
46        field_dict: dict[str, Any] = {}
47        field_dict.update(self.additional_properties)
48        field_dict.update(
49            {
50                "datasetId": dataset_id,
51                "importId": import_id,
52                "jobId": job_id,
53                "status": status,
54            }
55        )
56
57        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
59    @classmethod
60    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
61        d = dict(src_dict)
62        dataset_id = d.pop("datasetId")
63
64        import_id = d.pop("importId")
65
66        job_id = d.pop("jobId")
67
68        status = DatasetImportCreatedStatus(d.pop("status"))
69
70        dataset_import_created = cls(
71            dataset_id=dataset_id,
72            import_id=import_id,
73            job_id=job_id,
74            status=status,
75        )
76
77        dataset_import_created.additional_properties = d
78        return dataset_import_created
additional_keys: list[str]
80    @property
81    def additional_keys(self) -> list[str]:
82        return list(self.additional_properties.keys())
class DatasetImportCreatedStatus(builtins.str, enum.Enum):
5class DatasetImportCreatedStatus(str, Enum):
6    FETCHING = "fetching"
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'.

FETCHING = <DatasetImportCreatedStatus.FETCHING: 'fetching'>
class DatasetImportDexRequest:
 18@_attrs_define
 19class DatasetImportDexRequest:
 20    """The `dex` source's own fields — required when `type` is `dex`. `id`/`version` are required
 21    for a plain (native-cadence) import; both are ignored if the top-level `cadence` requested
 22    pre-aggregated candles instead, since that path needs neither a protocol nor a version
 23    distinction.
 24
 25        Example:
 26            {'network': 'ethereum', 'id': 'uniswap', 'version': 'v3', 'contract':
 27                '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'}
 28
 29        Attributes:
 30            network (DatasetImportDexRequestNetwork): Which chain the pool/pair lives on. Example: ethereum.
 31            contract (str): The pool (v3) or pair (v2) contract address. Example:
 32                0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640.
 33            id (DatasetImportDexRequestId | Unset): Which on-chain DEX protocol `contract` implements. Required unless the
 34                top-level
 35                `cadence` requested pre-aggregated candles, in which case it's ignored.
 36                 Example: uniswap.
 37            version (DatasetImportDexRequestVersion | Unset): Uniswap version the pool/pair contract implements. Required
 38                unless the top-level
 39                `cadence` requested pre-aggregated candles, in which case it's ignored.
 40                 Example: v3.
 41            factory (str | Unset): The factory that deployed `contract`. Optional — when omitted, it is discovered
 42                on-chain from `contract` itself at fetch time. Supply it explicitly only if you
 43                already know it, or the pool/pair belongs to a factory other than the canonical one
 44                for `network`/`version`. Either way, the pool/pair is validated against whichever
 45                factory is used before anything is fetched — a wrong or unrelated factory fails the
 46                import rather than silently fetching from the wrong pool. Ignored if the top-level
 47                `cadence` requested pre-aggregated candles.
 48    """
 49
 50    network: DatasetImportDexRequestNetwork
 51    contract: str
 52    id: DatasetImportDexRequestId | Unset = UNSET
 53    version: DatasetImportDexRequestVersion | Unset = UNSET
 54    factory: str | Unset = UNSET
 55    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 56
 57    def to_dict(self) -> dict[str, Any]:
 58        network = self.network.value
 59
 60        contract = self.contract
 61
 62        id: str | Unset = UNSET
 63        if not isinstance(self.id, Unset):
 64            id = self.id.value
 65
 66        version: str | Unset = UNSET
 67        if not isinstance(self.version, Unset):
 68            version = self.version.value
 69
 70        factory = self.factory
 71
 72        field_dict: dict[str, Any] = {}
 73        field_dict.update(self.additional_properties)
 74        field_dict.update(
 75            {
 76                "network": network,
 77                "contract": contract,
 78            }
 79        )
 80        if id is not UNSET:
 81            field_dict["id"] = id
 82        if version is not UNSET:
 83            field_dict["version"] = version
 84        if factory is not UNSET:
 85            field_dict["factory"] = factory
 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        network = DatasetImportDexRequestNetwork(d.pop("network"))
 93
 94        contract = d.pop("contract")
 95
 96        _id = d.pop("id", UNSET)
 97        id: DatasetImportDexRequestId | Unset
 98        if isinstance(_id, Unset):
 99            id = UNSET
100        else:
101            id = DatasetImportDexRequestId(_id)
102
103        _version = d.pop("version", UNSET)
104        version: DatasetImportDexRequestVersion | Unset
105        if isinstance(_version, Unset):
106            version = UNSET
107        else:
108            version = DatasetImportDexRequestVersion(_version)
109
110        factory = d.pop("factory", UNSET)
111
112        dataset_import_dex_request = cls(
113            network=network,
114            contract=contract,
115            id=id,
116            version=version,
117            factory=factory,
118        )
119
120        dataset_import_dex_request.additional_properties = d
121        return dataset_import_dex_request
122
123    @property
124    def additional_keys(self) -> list[str]:
125        return list(self.additional_properties.keys())
126
127    def __getitem__(self, key: str) -> Any:
128        return self.additional_properties[key]
129
130    def __setitem__(self, key: str, value: Any) -> None:
131        self.additional_properties[key] = value
132
133    def __delitem__(self, key: str) -> None:
134        del self.additional_properties[key]
135
136    def __contains__(self, key: str) -> bool:
137        return key in self.additional_properties

The dex source's own fields — required when type is dex. id/version are required for a plain (native-cadence) import; both are ignored if the top-level cadence requested pre-aggregated candles instead, since that path needs neither a protocol nor a version distinction.

Example:
    {'network': 'ethereum', 'id': 'uniswap', 'version': 'v3', 'contract':
        '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'}

Attributes:
    network (DatasetImportDexRequestNetwork): Which chain the pool/pair lives on. Example: ethereum.
    contract (str): The pool (v3) or pair (v2) contract address. Example:
        0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640.
    id (DatasetImportDexRequestId | Unset): Which on-chain DEX protocol `contract` implements. Required unless the
        top-level
        `cadence` requested pre-aggregated candles, in which case it's ignored.
         Example: uniswap.
    version (DatasetImportDexRequestVersion | Unset): Uniswap version the pool/pair contract implements. Required
        unless the top-level
        `cadence` requested pre-aggregated candles, in which case it's ignored.
         Example: v3.
    factory (str | Unset): The factory that deployed `contract`. Optional — when omitted, it is discovered
        on-chain from `contract` itself at fetch time. Supply it explicitly only if you
        already know it, or the pool/pair belongs to a factory other than the canonical one
        for `network`/`version`. Either way, the pool/pair is validated against whichever
        factory is used before anything is fetched — a wrong or unrelated factory fails the
        import rather than silently fetching from the wrong pool. Ignored if the top-level
        `cadence` requested pre-aggregated candles.
DatasetImportDexRequest( network: DatasetImportDexRequestNetwork, contract: str, id: DatasetImportDexRequestId | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, version: DatasetImportDexRequestVersion | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, factory: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
28def __init__(self, network, contract, id=attr_dict['id'].default, version=attr_dict['version'].default, factory=attr_dict['factory'].default):
29    self.network = network
30    self.contract = contract
31    self.id = id
32    self.version = version
33    self.factory = factory
34    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class DatasetImportDexRequest.

contract: str
id: DatasetImportDexRequestId | qtsurfer.api.client._generated.types.Unset
version: DatasetImportDexRequestVersion | qtsurfer.api.client._generated.types.Unset
factory: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
57    def to_dict(self) -> dict[str, Any]:
58        network = self.network.value
59
60        contract = self.contract
61
62        id: str | Unset = UNSET
63        if not isinstance(self.id, Unset):
64            id = self.id.value
65
66        version: str | Unset = UNSET
67        if not isinstance(self.version, Unset):
68            version = self.version.value
69
70        factory = self.factory
71
72        field_dict: dict[str, Any] = {}
73        field_dict.update(self.additional_properties)
74        field_dict.update(
75            {
76                "network": network,
77                "contract": contract,
78            }
79        )
80        if id is not UNSET:
81            field_dict["id"] = id
82        if version is not UNSET:
83            field_dict["version"] = version
84        if factory is not UNSET:
85            field_dict["factory"] = factory
86
87        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 89    @classmethod
 90    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 91        d = dict(src_dict)
 92        network = DatasetImportDexRequestNetwork(d.pop("network"))
 93
 94        contract = d.pop("contract")
 95
 96        _id = d.pop("id", UNSET)
 97        id: DatasetImportDexRequestId | Unset
 98        if isinstance(_id, Unset):
 99            id = UNSET
100        else:
101            id = DatasetImportDexRequestId(_id)
102
103        _version = d.pop("version", UNSET)
104        version: DatasetImportDexRequestVersion | Unset
105        if isinstance(_version, Unset):
106            version = UNSET
107        else:
108            version = DatasetImportDexRequestVersion(_version)
109
110        factory = d.pop("factory", UNSET)
111
112        dataset_import_dex_request = cls(
113            network=network,
114            contract=contract,
115            id=id,
116            version=version,
117            factory=factory,
118        )
119
120        dataset_import_dex_request.additional_properties = d
121        return dataset_import_dex_request
additional_keys: list[str]
123    @property
124    def additional_keys(self) -> list[str]:
125        return list(self.additional_properties.keys())
class DatasetImportDexRequestId(builtins.str, enum.Enum):
5class DatasetImportDexRequestId(str, Enum):
6    UNISWAP = "uniswap"
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'.

UNISWAP = <DatasetImportDexRequestId.UNISWAP: 'uniswap'>
class DatasetImportDexRequestNetwork(builtins.str, enum.Enum):
 5class DatasetImportDexRequestNetwork(str, Enum):
 6    ETHEREUM = "ethereum"
 7    ROBINHOOD = "robinhood"
 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'.

ETHEREUM = <DatasetImportDexRequestNetwork.ETHEREUM: 'ethereum'>
ROBINHOOD = <DatasetImportDexRequestNetwork.ROBINHOOD: 'robinhood'>
class DatasetImportDexRequestVersion(builtins.str, enum.Enum):
 5class DatasetImportDexRequestVersion(str, Enum):
 6    V2 = "v2"
 7    V3 = "v3"
 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'.

class DatasetImportRequest:
 23@_attrs_define
 24class DatasetImportRequest:
 25    """`POST /datasets/imports`'s request body. A common block plus one type-specific block,
 26    selected by `type` — `dex` is the only value today.
 27
 28        Attributes:
 29            name (str): A name unique among your datasets. `409` if already taken. Example: weth-usdc-week.
 30            instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
 31            from_ (datetime.datetime): Start of the range to fetch, inclusive. Must be before `to`. Example:
 32                2026-08-01T00:00:00Z.
 33            to (datetime.datetime): End of the range to fetch, exclusive. The total span is capped by your tier — a
 34                request wider than that ceiling is `400`, regardless of source type.
 35                 Example: 2026-08-08T00:00:00Z.
 36            type_ (DatasetImportRequestType): The source to fetch from. `dex` is the only value today. Example: dex.
 37            cadence (DatasetImportRequestCadence | Unset): Optional. Omitted/blank keeps native per-trade event cadence —
 38                each swap at its own
 39                timestamp, so the resulting version's `cadence` is `rt` unless the swaps happen to sit
 40                on a fixed grid (see `DatasetVersion.cadence`). Set to `1s`, `1m` or
 41                `5m` instead to get pre-aggregated candles at that width rather than raw trades (the
 42                resulting dataset's `type` becomes `klines`); any other value is `400`. Not every
 43                network supports every cadence — an unsupported combination fails asynchronously, not
 44                at request time (see `DatasetImportState.error`).
 45            dex (DatasetImportDexRequest | Unset): The `dex` source's own fields — required when `type` is `dex`.
 46                `id`/`version` are required
 47                for a plain (native-cadence) import; both are ignored if the top-level `cadence` requested
 48                pre-aggregated candles instead, since that path needs neither a protocol nor a version
 49                distinction.
 50                 Example: {'network': 'ethereum', 'id': 'uniswap', 'version': 'v3', 'contract':
 51                '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'}.
 52    """
 53
 54    name: str
 55    instrument: str
 56    from_: datetime.datetime
 57    to: datetime.datetime
 58    type_: DatasetImportRequestType
 59    cadence: DatasetImportRequestCadence | Unset = UNSET
 60    dex: DatasetImportDexRequest | Unset = UNSET
 61    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 62
 63    def to_dict(self) -> dict[str, Any]:
 64        name = self.name
 65
 66        instrument = self.instrument
 67
 68        from_ = self.from_.isoformat()
 69
 70        to = self.to.isoformat()
 71
 72        type_ = self.type_.value
 73
 74        cadence: str | Unset = UNSET
 75        if not isinstance(self.cadence, Unset):
 76            cadence = self.cadence.value
 77
 78        dex: dict[str, Any] | Unset = UNSET
 79        if not isinstance(self.dex, Unset):
 80            dex = self.dex.to_dict()
 81
 82        field_dict: dict[str, Any] = {}
 83        field_dict.update(self.additional_properties)
 84        field_dict.update(
 85            {
 86                "name": name,
 87                "instrument": instrument,
 88                "from": from_,
 89                "to": to,
 90                "type": type_,
 91            }
 92        )
 93        if cadence is not UNSET:
 94            field_dict["cadence"] = cadence
 95        if dex is not UNSET:
 96            field_dict["dex"] = dex
 97
 98        return field_dict
 99
100    @classmethod
101    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
102        from ..models.dataset_import_dex_request import DatasetImportDexRequest
103
104        d = dict(src_dict)
105        name = d.pop("name")
106
107        instrument = d.pop("instrument")
108
109        from_ = isoparse(d.pop("from"))
110
111        to = isoparse(d.pop("to"))
112
113        type_ = DatasetImportRequestType(d.pop("type"))
114
115        _cadence = d.pop("cadence", UNSET)
116        cadence: DatasetImportRequestCadence | Unset
117        if isinstance(_cadence, Unset):
118            cadence = UNSET
119        else:
120            cadence = DatasetImportRequestCadence(_cadence)
121
122        _dex = d.pop("dex", UNSET)
123        dex: DatasetImportDexRequest | Unset
124        if isinstance(_dex, Unset):
125            dex = UNSET
126        else:
127            dex = DatasetImportDexRequest.from_dict(_dex)
128
129        dataset_import_request = cls(
130            name=name,
131            instrument=instrument,
132            from_=from_,
133            to=to,
134            type_=type_,
135            cadence=cadence,
136            dex=dex,
137        )
138
139        dataset_import_request.additional_properties = d
140        return dataset_import_request
141
142    @property
143    def additional_keys(self) -> list[str]:
144        return list(self.additional_properties.keys())
145
146    def __getitem__(self, key: str) -> Any:
147        return self.additional_properties[key]
148
149    def __setitem__(self, key: str, value: Any) -> None:
150        self.additional_properties[key] = value
151
152    def __delitem__(self, key: str) -> None:
153        del self.additional_properties[key]
154
155    def __contains__(self, key: str) -> bool:
156        return key in self.additional_properties

POST /datasets/imports's request body. A common block plus one type-specific block, selected by type — dex is the only value today.

Attributes:
    name (str): A name unique among your datasets. `409` if already taken. Example: weth-usdc-week.
    instrument (str): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
    from_ (datetime.datetime): Start of the range to fetch, inclusive. Must be before `to`. Example:
        2026-08-01T00:00:00Z.
    to (datetime.datetime): End of the range to fetch, exclusive. The total span is capped by your tier — a
        request wider than that ceiling is `400`, regardless of source type.
         Example: 2026-08-08T00:00:00Z.
    type_ (DatasetImportRequestType): The source to fetch from. `dex` is the only value today. Example: dex.
    cadence (DatasetImportRequestCadence | Unset): Optional. Omitted/blank keeps native per-trade event cadence —
        each swap at its own
        timestamp, so the resulting version's `cadence` is `rt` unless the swaps happen to sit
        on a fixed grid (see `DatasetVersion.cadence`). Set to `1s`, `1m` or
        `5m` instead to get pre-aggregated candles at that width rather than raw trades (the
        resulting dataset's `type` becomes `klines`); any other value is `400`. Not every
        network supports every cadence — an unsupported combination fails asynchronously, not
        at request time (see `DatasetImportState.error`).
    dex (DatasetImportDexRequest | Unset): The `dex` source's own fields — required when `type` is `dex`.
        `id`/`version` are required
        for a plain (native-cadence) import; both are ignored if the top-level `cadence` requested
        pre-aggregated candles instead, since that path needs neither a protocol nor a version
        distinction.
         Example: {'network': 'ethereum', 'id': 'uniswap', 'version': 'v3', 'contract':
        '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'}.
DatasetImportRequest( name: str, instrument: str, from_: datetime.datetime, to: datetime.datetime, type_: DatasetImportRequestType, cadence: DatasetImportRequestCadence | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, dex: DatasetImportDexRequest | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
30def __init__(self, name, instrument, from_, to, type_, cadence=attr_dict['cadence'].default, dex=attr_dict['dex'].default):
31    self.name = name
32    self.instrument = instrument
33    self.from_ = from_
34    self.to = to
35    self.type_ = type_
36    self.cadence = cadence
37    self.dex = dex
38    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class DatasetImportRequest.

name: str
instrument: str
from_: datetime.datetime
to: datetime.datetime
cadence: DatasetImportRequestCadence | qtsurfer.api.client._generated.types.Unset
dex: DatasetImportDexRequest | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
63    def to_dict(self) -> dict[str, Any]:
64        name = self.name
65
66        instrument = self.instrument
67
68        from_ = self.from_.isoformat()
69
70        to = self.to.isoformat()
71
72        type_ = self.type_.value
73
74        cadence: str | Unset = UNSET
75        if not isinstance(self.cadence, Unset):
76            cadence = self.cadence.value
77
78        dex: dict[str, Any] | Unset = UNSET
79        if not isinstance(self.dex, Unset):
80            dex = self.dex.to_dict()
81
82        field_dict: dict[str, Any] = {}
83        field_dict.update(self.additional_properties)
84        field_dict.update(
85            {
86                "name": name,
87                "instrument": instrument,
88                "from": from_,
89                "to": to,
90                "type": type_,
91            }
92        )
93        if cadence is not UNSET:
94            field_dict["cadence"] = cadence
95        if dex is not UNSET:
96            field_dict["dex"] = dex
97
98        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
100    @classmethod
101    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
102        from ..models.dataset_import_dex_request import DatasetImportDexRequest
103
104        d = dict(src_dict)
105        name = d.pop("name")
106
107        instrument = d.pop("instrument")
108
109        from_ = isoparse(d.pop("from"))
110
111        to = isoparse(d.pop("to"))
112
113        type_ = DatasetImportRequestType(d.pop("type"))
114
115        _cadence = d.pop("cadence", UNSET)
116        cadence: DatasetImportRequestCadence | Unset
117        if isinstance(_cadence, Unset):
118            cadence = UNSET
119        else:
120            cadence = DatasetImportRequestCadence(_cadence)
121
122        _dex = d.pop("dex", UNSET)
123        dex: DatasetImportDexRequest | Unset
124        if isinstance(_dex, Unset):
125            dex = UNSET
126        else:
127            dex = DatasetImportDexRequest.from_dict(_dex)
128
129        dataset_import_request = cls(
130            name=name,
131            instrument=instrument,
132            from_=from_,
133            to=to,
134            type_=type_,
135            cadence=cadence,
136            dex=dex,
137        )
138
139        dataset_import_request.additional_properties = d
140        return dataset_import_request
additional_keys: list[str]
142    @property
143    def additional_keys(self) -> list[str]:
144        return list(self.additional_properties.keys())
class DatasetImportRequestCadence(builtins.str, enum.Enum):
 5class DatasetImportRequestCadence(str, Enum):
 6    VALUE_0 = "1s"
 7    VALUE_1 = "1m"
 8    VALUE_2 = "5m"
 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'.

class DatasetImportRequestType(builtins.str, enum.Enum):
5class DatasetImportRequestType(str, Enum):
6    DEX = "dex"
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'.

class DatasetImportState:
 20@_attrs_define
 21class DatasetImportState:
 22    """Progress of one import, from fetching through ingest. `fetching` is the one status only an
 23    import ever reports — an upload's file already exists by the time you can poll it; an
 24    import's doesn't, until this source finishes fetching it.
 25
 26        Attributes:
 27            import_id (str):  Example: imp_01j9z1x2y3z4a5b6c7d8e9f0g1.
 28            status (DatasetImportStateStatus): * `fetching` — reading from the source; nothing staged yet.
 29                * `ingesting` — fetch complete, staged, and re-entered the same ingest chain an
 30                  upload uses; the worker is parsing and validating it.
 31                * `ready` — ingested successfully. `version` carries the result.
 32                * `failed` — the fetch or the ingest that followed it was rejected. `error` names why.
 33                 Example: ready.
 34            job_id (str | Unset): The fetch/ingest job id, while `status` is `fetching` or `ingesting`.
 35            error (str | Unset): A human-readable reason, present when `status` is `failed` — an unresolvable
 36                pool/pair, no data in the requested range, a range older than the configured source
 37                retains, the fetch exceeding your tier's time ceiling, or any of
 38                `DatasetUploadState.error`'s own ingest-side reasons once fetching hands off to it.
 39                Durably recorded, same as on the upload path.
 40                 Example: Import exceeded the tier's 12 minute ceiling.
 41            version (DatasetVersion | Unset): One successfully ingested upload. Cadence and timestamp unit are discovered
 42                from the file,
 43                not declared by the caller.
 44    """
 45
 46    import_id: str
 47    status: DatasetImportStateStatus
 48    job_id: str | Unset = UNSET
 49    error: str | Unset = UNSET
 50    version: DatasetVersion | Unset = UNSET
 51    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 52
 53    def to_dict(self) -> dict[str, Any]:
 54        import_id = self.import_id
 55
 56        status = self.status.value
 57
 58        job_id = self.job_id
 59
 60        error = self.error
 61
 62        version: dict[str, Any] | Unset = UNSET
 63        if not isinstance(self.version, Unset):
 64            version = self.version.to_dict()
 65
 66        field_dict: dict[str, Any] = {}
 67        field_dict.update(self.additional_properties)
 68        field_dict.update(
 69            {
 70                "importId": import_id,
 71                "status": status,
 72            }
 73        )
 74        if job_id is not UNSET:
 75            field_dict["jobId"] = job_id
 76        if error is not UNSET:
 77            field_dict["error"] = error
 78        if version is not UNSET:
 79            field_dict["version"] = version
 80
 81        return field_dict
 82
 83    @classmethod
 84    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 85        from ..models.dataset_version import DatasetVersion
 86
 87        d = dict(src_dict)
 88        import_id = d.pop("importId")
 89
 90        status = DatasetImportStateStatus(d.pop("status"))
 91
 92        job_id = d.pop("jobId", UNSET)
 93
 94        error = d.pop("error", UNSET)
 95
 96        _version = d.pop("version", UNSET)
 97        version: DatasetVersion | Unset
 98        if isinstance(_version, Unset):
 99            version = UNSET
100        else:
101            version = DatasetVersion.from_dict(_version)
102
103        dataset_import_state = cls(
104            import_id=import_id,
105            status=status,
106            job_id=job_id,
107            error=error,
108            version=version,
109        )
110
111        dataset_import_state.additional_properties = d
112        return dataset_import_state
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

Progress of one import, from fetching through ingest. fetching is the one status only an import ever reports — an upload's file already exists by the time you can poll it; an import's doesn't, until this source finishes fetching it.

Attributes:
    import_id (str):  Example: imp_01j9z1x2y3z4a5b6c7d8e9f0g1.
    status (DatasetImportStateStatus): * `fetching` — reading from the source; nothing staged yet.
        * `ingesting` — fetch complete, staged, and re-entered the same ingest chain an
          upload uses; the worker is parsing and validating it.
        * `ready` — ingested successfully. `version` carries the result.
        * `failed` — the fetch or the ingest that followed it was rejected. `error` names why.
         Example: ready.
    job_id (str | Unset): The fetch/ingest job id, while `status` is `fetching` or `ingesting`.
    error (str | Unset): A human-readable reason, present when `status` is `failed` — an unresolvable
        pool/pair, no data in the requested range, a range older than the configured source
        retains, the fetch exceeding your tier's time ceiling, or any of
        `DatasetUploadState.error`'s own ingest-side reasons once fetching hands off to it.
        Durably recorded, same as on the upload path.
         Example: Import exceeded the tier's 12 minute ceiling.
    version (DatasetVersion | Unset): One successfully ingested upload. Cadence and timestamp unit are discovered
        from the file,
        not declared by the caller.
DatasetImportState( import_id: str, status: DatasetImportStateStatus, job_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, error: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, version: DatasetVersion | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
28def __init__(self, import_id, status, job_id=attr_dict['job_id'].default, error=attr_dict['error'].default, version=attr_dict['version'].default):
29    self.import_id = import_id
30    self.status = status
31    self.job_id = job_id
32    self.error = error
33    self.version = version
34    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class DatasetImportState.

import_id: str
job_id: str | qtsurfer.api.client._generated.types.Unset
error: str | qtsurfer.api.client._generated.types.Unset
version: DatasetVersion | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
53    def to_dict(self) -> dict[str, Any]:
54        import_id = self.import_id
55
56        status = self.status.value
57
58        job_id = self.job_id
59
60        error = self.error
61
62        version: dict[str, Any] | Unset = UNSET
63        if not isinstance(self.version, Unset):
64            version = self.version.to_dict()
65
66        field_dict: dict[str, Any] = {}
67        field_dict.update(self.additional_properties)
68        field_dict.update(
69            {
70                "importId": import_id,
71                "status": status,
72            }
73        )
74        if job_id is not UNSET:
75            field_dict["jobId"] = job_id
76        if error is not UNSET:
77            field_dict["error"] = error
78        if version is not UNSET:
79            field_dict["version"] = version
80
81        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 83    @classmethod
 84    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 85        from ..models.dataset_version import DatasetVersion
 86
 87        d = dict(src_dict)
 88        import_id = d.pop("importId")
 89
 90        status = DatasetImportStateStatus(d.pop("status"))
 91
 92        job_id = d.pop("jobId", UNSET)
 93
 94        error = d.pop("error", UNSET)
 95
 96        _version = d.pop("version", UNSET)
 97        version: DatasetVersion | Unset
 98        if isinstance(_version, Unset):
 99            version = UNSET
100        else:
101            version = DatasetVersion.from_dict(_version)
102
103        dataset_import_state = cls(
104            import_id=import_id,
105            status=status,
106            job_id=job_id,
107            error=error,
108            version=version,
109        )
110
111        dataset_import_state.additional_properties = d
112        return dataset_import_state
additional_keys: list[str]
114    @property
115    def additional_keys(self) -> list[str]:
116        return list(self.additional_properties.keys())
class DatasetImportStateStatus(builtins.str, enum.Enum):
 5class DatasetImportStateStatus(str, Enum):
 6    FAILED = "failed"
 7    FETCHING = "fetching"
 8    INGESTING = "ingesting"
 9    READY = "ready"
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'.

FAILED = <DatasetImportStateStatus.FAILED: 'failed'>
FETCHING = <DatasetImportStateStatus.FETCHING: 'fetching'>
INGESTING = <DatasetImportStateStatus.INGESTING: 'ingesting'>
READY = <DatasetImportStateStatus.READY: 'ready'>
class DatasetStatus(builtins.str, enum.Enum):
 5class DatasetStatus(str, Enum):
 6    FAILED = "failed"
 7    PENDING = "pending"
 8    READY = "ready"
 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'.

FAILED = <DatasetStatus.FAILED: 'failed'>
PENDING = <DatasetStatus.PENDING: 'pending'>
READY = <DatasetStatus.READY: 'ready'>
class DatasetTimestampUnit(builtins.str, enum.Enum):
 5class DatasetTimestampUnit(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'.

ISO = <DatasetTimestampUnit.ISO: 'iso'>
class DatasetType(builtins.str, enum.Enum):
 5class DatasetType(str, Enum):
 6    KLINES = "klines"
 7    TICKER = "ticker"
 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'.

KLINES = <DatasetType.KLINES: 'klines'>
TICKER = <DatasetType.TICKER: 'ticker'>
class DatasetUploadSession:
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.
DatasetUploadSession( upload_id: str, upload: DatasetUploadTarget)
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.

upload_id: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
67    @property
68    def additional_keys(self) -> list[str]:
69        return list(self.additional_properties.keys())
class DatasetUploadState:
 20@_attrs_define
 21class DatasetUploadState:
 22    """Progress of one upload, from staged through ingest. Durably recorded 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, a
 34                  `.zip` with no file inside or more than one).
 35                 Example: ready.
 36            job_id (str | Unset): The ingest job id, while `status` is `ingesting`.
 37            error (str | Unset): A human-readable reason, present when `status` is `failed` (e.g. bad CSV contract,
 38                mixed timestamp units, a `.zip` with no file inside or more than one). Durably
 39                recorded alongside the failure itself, so it stays available however long after the
 40                fact you poll — not tied to how recently the failure happened.
 41                 Example: line 3: column 'close' is not a number: not-a-number.
 42            version (DatasetVersion | Unset): One successfully ingested upload. Cadence and timestamp unit are discovered
 43                from the file,
 44                not declared by the caller.
 45    """
 46
 47    upload_id: str
 48    status: DatasetUploadStateStatus
 49    job_id: str | Unset = UNSET
 50    error: str | Unset = UNSET
 51    version: DatasetVersion | Unset = UNSET
 52    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 53
 54    def to_dict(self) -> dict[str, Any]:
 55        upload_id = self.upload_id
 56
 57        status = self.status.value
 58
 59        job_id = self.job_id
 60
 61        error = self.error
 62
 63        version: dict[str, Any] | Unset = UNSET
 64        if not isinstance(self.version, Unset):
 65            version = self.version.to_dict()
 66
 67        field_dict: dict[str, Any] = {}
 68        field_dict.update(self.additional_properties)
 69        field_dict.update(
 70            {
 71                "uploadId": upload_id,
 72                "status": status,
 73            }
 74        )
 75        if job_id is not UNSET:
 76            field_dict["jobId"] = job_id
 77        if error is not UNSET:
 78            field_dict["error"] = error
 79        if version is not UNSET:
 80            field_dict["version"] = version
 81
 82        return field_dict
 83
 84    @classmethod
 85    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 86        from ..models.dataset_version import DatasetVersion
 87
 88        d = dict(src_dict)
 89        upload_id = d.pop("uploadId")
 90
 91        status = DatasetUploadStateStatus(d.pop("status"))
 92
 93        job_id = d.pop("jobId", UNSET)
 94
 95        error = d.pop("error", UNSET)
 96
 97        _version = d.pop("version", UNSET)
 98        version: DatasetVersion | Unset
 99        if isinstance(_version, Unset):
100            version = UNSET
101        else:
102            version = DatasetVersion.from_dict(_version)
103
104        dataset_upload_state = cls(
105            upload_id=upload_id,
106            status=status,
107            job_id=job_id,
108            error=error,
109            version=version,
110        )
111
112        dataset_upload_state.additional_properties = d
113        return dataset_upload_state
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

Progress of one upload, from staged through ingest. Durably recorded 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, a
          `.zip` with no file inside or more than one).
         Example: ready.
    job_id (str | Unset): The ingest job id, while `status` is `ingesting`.
    error (str | Unset): A human-readable reason, present when `status` is `failed` (e.g. bad CSV contract,
        mixed timestamp units, a `.zip` with no file inside or more than one). Durably
        recorded alongside the failure itself, so it stays available however long after the
        fact you poll — not tied to how recently the failure happened.
         Example: line 3: column 'close' is not a number: not-a-number.
    version (DatasetVersion | Unset): One successfully ingested upload. Cadence and timestamp unit are discovered
        from the file,
        not declared by the caller.
DatasetUploadState( upload_id: str, status: DatasetUploadStateStatus, job_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, error: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, version: DatasetVersion | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
28def __init__(self, upload_id, status, job_id=attr_dict['job_id'].default, error=attr_dict['error'].default, version=attr_dict['version'].default):
29    self.upload_id = upload_id
30    self.status = status
31    self.job_id = job_id
32    self.error = error
33    self.version = version
34    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class DatasetUploadState.

upload_id: str
job_id: str | qtsurfer.api.client._generated.types.Unset
error: str | qtsurfer.api.client._generated.types.Unset
version: DatasetVersion | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
54    def to_dict(self) -> dict[str, Any]:
55        upload_id = self.upload_id
56
57        status = self.status.value
58
59        job_id = self.job_id
60
61        error = self.error
62
63        version: dict[str, Any] | Unset = UNSET
64        if not isinstance(self.version, Unset):
65            version = self.version.to_dict()
66
67        field_dict: dict[str, Any] = {}
68        field_dict.update(self.additional_properties)
69        field_dict.update(
70            {
71                "uploadId": upload_id,
72                "status": status,
73            }
74        )
75        if job_id is not UNSET:
76            field_dict["jobId"] = job_id
77        if error is not UNSET:
78            field_dict["error"] = error
79        if version is not UNSET:
80            field_dict["version"] = version
81
82        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 84    @classmethod
 85    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 86        from ..models.dataset_version import DatasetVersion
 87
 88        d = dict(src_dict)
 89        upload_id = d.pop("uploadId")
 90
 91        status = DatasetUploadStateStatus(d.pop("status"))
 92
 93        job_id = d.pop("jobId", UNSET)
 94
 95        error = d.pop("error", UNSET)
 96
 97        _version = d.pop("version", UNSET)
 98        version: DatasetVersion | Unset
 99        if isinstance(_version, Unset):
100            version = UNSET
101        else:
102            version = DatasetVersion.from_dict(_version)
103
104        dataset_upload_state = cls(
105            upload_id=upload_id,
106            status=status,
107            job_id=job_id,
108            error=error,
109            version=version,
110        )
111
112        dataset_upload_state.additional_properties = d
113        return dataset_upload_state
additional_keys: list[str]
115    @property
116    def additional_keys(self) -> list[str]:
117        return list(self.additional_properties.keys())
class DatasetUploadStateStatus(builtins.str, enum.Enum):
 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'.

FAILED = <DatasetUploadStateStatus.FAILED: 'failed'>
INGESTING = <DatasetUploadStateStatus.INGESTING: 'ingesting'>
READY = <DatasetUploadStateStatus.READY: 'ready'>
UPLOADING = <DatasetUploadStateStatus.UPLOADING: 'uploading'>
class DatasetUploadTarget:
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 file here directly — the CSV or parquet itself, or a `.gz`/`.zip` of it
19            (see `createDataset`'s own description) — no `Authorization` header, no other API
20            credentials.
21             Example: https://storage.qtsurfer.com/uploads/00000000-.../up_1a2b3c4d5e6f7a8b/raw.csv?X-Amz-....
22        expires_in_minutes (int): How long `url` stays valid. Example: 15.
23    """
24
25    url: str
26    expires_in_minutes: int
27    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
29    def to_dict(self) -> dict[str, Any]:
30        url = self.url
31
32        expires_in_minutes = self.expires_in_minutes
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "url": url,
39                "expiresInMinutes": expires_in_minutes,
40            }
41        )
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        url = d.pop("url")
49
50        expires_in_minutes = d.pop("expiresInMinutes")
51
52        dataset_upload_target = cls(
53            url=url,
54            expires_in_minutes=expires_in_minutes,
55        )
56
57        dataset_upload_target.additional_properties = d
58        return dataset_upload_target
59
60    @property
61    def additional_keys(self) -> list[str]:
62        return list(self.additional_properties.keys())
63
64    def __getitem__(self, key: str) -> Any:
65        return self.additional_properties[key]
66
67    def __setitem__(self, key: str, value: Any) -> None:
68        self.additional_properties[key] = value
69
70    def __delitem__(self, key: str) -> None:
71        del self.additional_properties[key]
72
73    def __contains__(self, key: str) -> bool:
74        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 file here directly — the CSV or parquet itself, or a .gz/.zip of it (see createDataset's own description) — 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.

DatasetUploadTarget(url: str, expires_in_minutes: int)
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.

url: str
expires_in_minutes: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
29    def to_dict(self) -> dict[str, Any]:
30        url = self.url
31
32        expires_in_minutes = self.expires_in_minutes
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "url": url,
39                "expiresInMinutes": expires_in_minutes,
40            }
41        )
42
43        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
45    @classmethod
46    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
47        d = dict(src_dict)
48        url = d.pop("url")
49
50        expires_in_minutes = d.pop("expiresInMinutes")
51
52        dataset_upload_target = cls(
53            url=url,
54            expires_in_minutes=expires_in_minutes,
55        )
56
57        dataset_upload_target.additional_properties = d
58        return dataset_upload_target
additional_keys: list[str]
60    @property
61    def additional_keys(self) -> list[str]:
62        return list(self.additional_properties.keys())
class DatasetVersion:
 17@_attrs_define
 18class DatasetVersion:
 19    """One successfully ingested upload. Cadence and timestamp unit are discovered from the file,
 20    not declared by the caller.
 21
 22        Attributes:
 23            dataset_id (str):  Example: ds_3f9a1c2e7b0d4a5f.
 24            id (str | Unset): The version id. Pass as `datasetVersionId` on `POST .../prepare` to pin it. Example:
 25                dsv_8e2b4f19c6a03d7e.
 26            bytes_ (int | Unset): Size of the stored file `dataUrl` points at — a converted `lastra` for a CSV/gzip/zip
 27                upload, or the parquet file itself, unconverted, for a parquet upload. Not the size of the bytes originally PUT
 28                to storage; see `dataFormat`. Example: 4831022.
 29            rows (int | Unset): Number of data rows. Example: 86400.
 30            cadence (str | Unset): The cadence discovered from the data's own timestamps. Either a fixed grid — `1s`,
 31                `5s`, `15s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d` — when at least half the
 32                intervals between consecutive rows fall on that step (small clock jitter tolerated), or
 33                `rt`: native data at the rate it was captured, each row at its own timestamp with no
 34                fixed step — per-trade on-chain swaps, block-spaced or sub-second ticks, irregular
 35                intervals. An `rt` dataset can be resampled to any fixed cadence at prepare time.
 36                 Example: 1s.
 37            timestamp_unit (DatasetVersionTimestampUnit | Unset): The unit the `timestamp` column was uploaded in —
 38                ISO-8601, or the epoch band its
 39                numeric values fell in (seconds, millis, or micros).
 40                 Example: iso.
 41            gaps (int | Unset): Number of gaps at the discovered cadence. Always `0` for `rt`.
 42            largest_gap_steps (int | Unset): The largest gap, in units of the discovered cadence step. Always `0` for `rt`.
 43            data_url (str | Unset): Presigned GET URL to the stored file — see `dataFormat` for which format it's in.
 44                Present once the version is `ready`. Long-lived (day-scale, not permanent): a
 45                DuckDB-WASM/`lastra-ts`-style reader issues HTTP range requests against it lazily over
 46                an extended viewing session, not in one shot like a browser upload.
 47                 Example: https://storage.qtsurfer.com/00000000-
 48                .../ds_3f9a1c2e7b0d4a5f/dsv_8e2b4f19c6a03d7e/ticker_BTC_USDT_1700000000000_1700086400000_1m.lastra?X-Amz-....
 49            data_format (DatasetVersionDataFormat | Unset): Which format `dataUrl` is actually in — check this rather than
 50                assuming it matches
 51                how you uploaded it. `lastra` — our native columnar format — for a CSV (or gzip/zip
 52                of one) upload, always converted on ingest, or for a lastra upload, stored as-is
 53                (the value alone doesn't tell you which). `parquet` for a parquet upload, also
 54                stored as-is today.
 55                 Example: lastra.
 56    """
 57
 58    dataset_id: str
 59    id: str | Unset = UNSET
 60    bytes_: int | Unset = UNSET
 61    rows: int | Unset = UNSET
 62    cadence: str | Unset = UNSET
 63    timestamp_unit: DatasetVersionTimestampUnit | Unset = UNSET
 64    gaps: int | Unset = UNSET
 65    largest_gap_steps: int | Unset = UNSET
 66    data_url: str | Unset = UNSET
 67    data_format: DatasetVersionDataFormat | Unset = UNSET
 68    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 69
 70    def to_dict(self) -> dict[str, Any]:
 71        dataset_id = self.dataset_id
 72
 73        id = self.id
 74
 75        bytes_ = self.bytes_
 76
 77        rows = self.rows
 78
 79        cadence = self.cadence
 80
 81        timestamp_unit: str | Unset = UNSET
 82        if not isinstance(self.timestamp_unit, Unset):
 83            timestamp_unit = self.timestamp_unit.value
 84
 85        gaps = self.gaps
 86
 87        largest_gap_steps = self.largest_gap_steps
 88
 89        data_url = self.data_url
 90
 91        data_format: str | Unset = UNSET
 92        if not isinstance(self.data_format, Unset):
 93            data_format = self.data_format.value
 94
 95        field_dict: dict[str, Any] = {}
 96        field_dict.update(self.additional_properties)
 97        field_dict.update(
 98            {
 99                "datasetId": dataset_id,
100            }
101        )
102        if id is not UNSET:
103            field_dict["id"] = id
104        if bytes_ is not UNSET:
105            field_dict["bytes"] = bytes_
106        if rows is not UNSET:
107            field_dict["rows"] = rows
108        if cadence is not UNSET:
109            field_dict["cadence"] = cadence
110        if timestamp_unit is not UNSET:
111            field_dict["timestampUnit"] = timestamp_unit
112        if gaps is not UNSET:
113            field_dict["gaps"] = gaps
114        if largest_gap_steps is not UNSET:
115            field_dict["largestGapSteps"] = largest_gap_steps
116        if data_url is not UNSET:
117            field_dict["dataUrl"] = data_url
118        if data_format is not UNSET:
119            field_dict["dataFormat"] = data_format
120
121        return field_dict
122
123    @classmethod
124    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
125        d = dict(src_dict)
126        dataset_id = d.pop("datasetId")
127
128        id = d.pop("id", UNSET)
129
130        bytes_ = d.pop("bytes", UNSET)
131
132        rows = d.pop("rows", UNSET)
133
134        cadence = d.pop("cadence", UNSET)
135
136        _timestamp_unit = d.pop("timestampUnit", UNSET)
137        timestamp_unit: DatasetVersionTimestampUnit | Unset
138        if isinstance(_timestamp_unit, Unset):
139            timestamp_unit = UNSET
140        else:
141            timestamp_unit = DatasetVersionTimestampUnit(_timestamp_unit)
142
143        gaps = d.pop("gaps", UNSET)
144
145        largest_gap_steps = d.pop("largestGapSteps", UNSET)
146
147        data_url = d.pop("dataUrl", UNSET)
148
149        _data_format = d.pop("dataFormat", UNSET)
150        data_format: DatasetVersionDataFormat | Unset
151        if isinstance(_data_format, Unset):
152            data_format = UNSET
153        else:
154            data_format = DatasetVersionDataFormat(_data_format)
155
156        dataset_version = cls(
157            dataset_id=dataset_id,
158            id=id,
159            bytes_=bytes_,
160            rows=rows,
161            cadence=cadence,
162            timestamp_unit=timestamp_unit,
163            gaps=gaps,
164            largest_gap_steps=largest_gap_steps,
165            data_url=data_url,
166            data_format=data_format,
167        )
168
169        dataset_version.additional_properties = d
170        return dataset_version
171
172    @property
173    def additional_keys(self) -> list[str]:
174        return list(self.additional_properties.keys())
175
176    def __getitem__(self, key: str) -> Any:
177        return self.additional_properties[key]
178
179    def __setitem__(self, key: str, value: Any) -> None:
180        self.additional_properties[key] = value
181
182    def __delitem__(self, key: str) -> None:
183        del self.additional_properties[key]
184
185    def __contains__(self, key: str) -> bool:
186        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 stored file `dataUrl` points at — a converted `lastra` for a CSV/gzip/zip
        upload, or the parquet file itself, unconverted, for a parquet upload. Not the size of the bytes originally PUT
        to storage; see `dataFormat`. Example: 4831022.
    rows (int | Unset): Number of data rows. Example: 86400.
    cadence (str | Unset): The cadence discovered from the data's own timestamps. Either a fixed grid — `1s`,
        `5s`, `15s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d` — when at least half the
        intervals between consecutive rows fall on that step (small clock jitter tolerated), or
        `rt`: native data at the rate it was captured, each row at its own timestamp with no
        fixed step — per-trade on-chain swaps, block-spaced or sub-second ticks, irregular
        intervals. An `rt` dataset can be resampled to any fixed cadence at prepare time.
         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. Always `0` for `rt`.
    largest_gap_steps (int | Unset): The largest gap, in units of the discovered cadence step. Always `0` for `rt`.
    data_url (str | Unset): Presigned GET URL to the stored file — see `dataFormat` for which format it's in.
        Present once the version is `ready`. Long-lived (day-scale, not permanent): a
        DuckDB-WASM/`lastra-ts`-style reader issues HTTP range requests against it lazily over
        an extended viewing session, not in one shot like a browser upload.
         Example: https://storage.qtsurfer.com/00000000-
        .../ds_3f9a1c2e7b0d4a5f/dsv_8e2b4f19c6a03d7e/ticker_BTC_USDT_1700000000000_1700086400000_1m.lastra?X-Amz-....
    data_format (DatasetVersionDataFormat | Unset): Which format `dataUrl` is actually in — check this rather than
        assuming it matches
        how you uploaded it. `lastra` — our native columnar format — for a CSV (or gzip/zip
        of one) upload, always converted on ingest, or for a lastra upload, stored as-is
        (the value alone doesn't tell you which). `parquet` for a parquet upload, also
        stored as-is today.
         Example: lastra.
DatasetVersion( dataset_id: str, id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, bytes_: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, rows: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cadence: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, timestamp_unit: DatasetVersionTimestampUnit | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, gaps: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, largest_gap_steps: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, data_url: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, data_format: DatasetVersionDataFormat | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
33def __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, data_url=attr_dict['data_url'].default, data_format=attr_dict['data_format'].default):
34    self.dataset_id = dataset_id
35    self.id = id
36    self.bytes_ = bytes_
37    self.rows = rows
38    self.cadence = cadence
39    self.timestamp_unit = timestamp_unit
40    self.gaps = gaps
41    self.largest_gap_steps = largest_gap_steps
42    self.data_url = data_url
43    self.data_format = data_format
44    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class DatasetVersion.

dataset_id: str
id: str | qtsurfer.api.client._generated.types.Unset
bytes_: int | qtsurfer.api.client._generated.types.Unset
rows: int | qtsurfer.api.client._generated.types.Unset
cadence: str | qtsurfer.api.client._generated.types.Unset
timestamp_unit: DatasetVersionTimestampUnit | qtsurfer.api.client._generated.types.Unset
gaps: int | qtsurfer.api.client._generated.types.Unset
largest_gap_steps: int | qtsurfer.api.client._generated.types.Unset
data_url: str | qtsurfer.api.client._generated.types.Unset
data_format: DatasetVersionDataFormat | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 70    def to_dict(self) -> dict[str, Any]:
 71        dataset_id = self.dataset_id
 72
 73        id = self.id
 74
 75        bytes_ = self.bytes_
 76
 77        rows = self.rows
 78
 79        cadence = self.cadence
 80
 81        timestamp_unit: str | Unset = UNSET
 82        if not isinstance(self.timestamp_unit, Unset):
 83            timestamp_unit = self.timestamp_unit.value
 84
 85        gaps = self.gaps
 86
 87        largest_gap_steps = self.largest_gap_steps
 88
 89        data_url = self.data_url
 90
 91        data_format: str | Unset = UNSET
 92        if not isinstance(self.data_format, Unset):
 93            data_format = self.data_format.value
 94
 95        field_dict: dict[str, Any] = {}
 96        field_dict.update(self.additional_properties)
 97        field_dict.update(
 98            {
 99                "datasetId": dataset_id,
100            }
101        )
102        if id is not UNSET:
103            field_dict["id"] = id
104        if bytes_ is not UNSET:
105            field_dict["bytes"] = bytes_
106        if rows is not UNSET:
107            field_dict["rows"] = rows
108        if cadence is not UNSET:
109            field_dict["cadence"] = cadence
110        if timestamp_unit is not UNSET:
111            field_dict["timestampUnit"] = timestamp_unit
112        if gaps is not UNSET:
113            field_dict["gaps"] = gaps
114        if largest_gap_steps is not UNSET:
115            field_dict["largestGapSteps"] = largest_gap_steps
116        if data_url is not UNSET:
117            field_dict["dataUrl"] = data_url
118        if data_format is not UNSET:
119            field_dict["dataFormat"] = data_format
120
121        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
123    @classmethod
124    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
125        d = dict(src_dict)
126        dataset_id = d.pop("datasetId")
127
128        id = d.pop("id", UNSET)
129
130        bytes_ = d.pop("bytes", UNSET)
131
132        rows = d.pop("rows", UNSET)
133
134        cadence = d.pop("cadence", UNSET)
135
136        _timestamp_unit = d.pop("timestampUnit", UNSET)
137        timestamp_unit: DatasetVersionTimestampUnit | Unset
138        if isinstance(_timestamp_unit, Unset):
139            timestamp_unit = UNSET
140        else:
141            timestamp_unit = DatasetVersionTimestampUnit(_timestamp_unit)
142
143        gaps = d.pop("gaps", UNSET)
144
145        largest_gap_steps = d.pop("largestGapSteps", UNSET)
146
147        data_url = d.pop("dataUrl", UNSET)
148
149        _data_format = d.pop("dataFormat", UNSET)
150        data_format: DatasetVersionDataFormat | Unset
151        if isinstance(_data_format, Unset):
152            data_format = UNSET
153        else:
154            data_format = DatasetVersionDataFormat(_data_format)
155
156        dataset_version = cls(
157            dataset_id=dataset_id,
158            id=id,
159            bytes_=bytes_,
160            rows=rows,
161            cadence=cadence,
162            timestamp_unit=timestamp_unit,
163            gaps=gaps,
164            largest_gap_steps=largest_gap_steps,
165            data_url=data_url,
166            data_format=data_format,
167        )
168
169        dataset_version.additional_properties = d
170        return dataset_version
additional_keys: list[str]
172    @property
173    def additional_keys(self) -> list[str]:
174        return list(self.additional_properties.keys())
class DatasetVersionDataFormat(builtins.str, enum.Enum):
 5class DatasetVersionDataFormat(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'.

LASTRA = <DatasetVersionDataFormat.LASTRA: 'lastra'>
PARQUET = <DatasetVersionDataFormat.PARQUET: 'parquet'>
class DatasetVersionTimestampUnit(builtins.str, enum.Enum):
 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'.

class DatasetWithLinksDataFormat(builtins.str, enum.Enum):
 5class DatasetWithLinksDataFormat(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'.

LASTRA = <DatasetWithLinksDataFormat.LASTRA: 'lastra'>
PARQUET = <DatasetWithLinksDataFormat.PARQUET: 'parquet'>
class DatasetWithLinksLinksSelf:
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.

DatasetWithLinksLinksSelf( href: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

href: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
48    @property
49    def additional_keys(self) -> list[str]:
50        return list(self.additional_properties.keys())
class DataSourceType(builtins.str, enum.Enum):
 5class DataSourceType(str, Enum):
 6    FUNDING = "funding"
 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'.

FUNDING = <DataSourceType.FUNDING: 'funding'>
KLINE = <DataSourceType.KLINE: 'kline'>
TICKER = <DataSourceType.TICKER: 'ticker'>
class DeclaredProperty:
 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.
DeclaredProperty( name: str, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, default_value: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, reflected: bool | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, min_: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, max_: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, step: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

name: str
description: str | qtsurfer.api.client._generated.types.Unset
default_value: str | qtsurfer.api.client._generated.types.Unset
reflected: bool | qtsurfer.api.client._generated.types.Unset
min_: float | qtsurfer.api.client._generated.types.Unset
max_: float | qtsurfer.api.client._generated.types.Unset
step: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
117    @property
118    def additional_keys(self) -> list[str]:
119        return list(self.additional_properties.keys())
class DeleteDatasetResponse200:
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):

DeleteDatasetResponse200(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.

dataset_id: str
deleted: bool
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
56    @property
57    def additional_keys(self) -> list[str]:
58        return list(self.additional_properties.keys())
class DeleteStrategyResponse200:
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. How much formatting the id ignores depends on
19            the language — see `POST /strategy` for exactly which rewrites preserve it and which do
20            not.
21             Example: 6bsh31ikwkuivhtgcoa6s4.
22        deleted (bool):
23    """
24
25    strategy_id: str
26    deleted: bool
27    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
29    def to_dict(self) -> dict[str, Any]:
30        strategy_id = self.strategy_id
31
32        deleted = self.deleted
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "strategyId": strategy_id,
39                "deleted": deleted,
40            }
41        )
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        strategy_id = d.pop("strategyId")
49
50        deleted = d.pop("deleted")
51
52        delete_strategy_response_200 = cls(
53            strategy_id=strategy_id,
54            deleted=deleted,
55        )
56
57        delete_strategy_response_200.additional_properties = d
58        return delete_strategy_response_200
59
60    @property
61    def additional_keys(self) -> list[str]:
62        return list(self.additional_properties.keys())
63
64    def __getitem__(self, key: str) -> Any:
65        return self.additional_properties[key]
66
67    def __setitem__(self, key: str, value: Any) -> None:
68        self.additional_properties[key] = value
69
70    def __delitem__(self, key: str) -> None:
71        del self.additional_properties[key]
72
73    def __contains__(self, key: str) -> bool:
74        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. How much formatting the id ignores depends on the language — see POST /strategy for exactly which rewrites preserve it and which do not. Example: 6bsh31ikwkuivhtgcoa6s4. deleted (bool):

DeleteStrategyResponse200(strategy_id: str, 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.

strategy_id: str
deleted: bool
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
29    def to_dict(self) -> dict[str, Any]:
30        strategy_id = self.strategy_id
31
32        deleted = self.deleted
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "strategyId": strategy_id,
39                "deleted": deleted,
40            }
41        )
42
43        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
45    @classmethod
46    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
47        d = dict(src_dict)
48        strategy_id = d.pop("strategyId")
49
50        deleted = d.pop("deleted")
51
52        delete_strategy_response_200 = cls(
53            strategy_id=strategy_id,
54            deleted=deleted,
55        )
56
57        delete_strategy_response_200.additional_properties = d
58        return delete_strategy_response_200
additional_keys: list[str]
60    @property
61    def additional_keys(self) -> list[str]:
62        return list(self.additional_properties.keys())
class DownloadKlinesFormat(builtins.str, enum.Enum):
 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'.

LASTRA = <DownloadKlinesFormat.LASTRA: 'lastra'>
PARQUET = <DownloadKlinesFormat.PARQUET: 'parquet'>
class DownloadTickersFormat(builtins.str, enum.Enum):
 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'.

LASTRA = <DownloadTickersFormat.LASTRA: 'lastra'>
PARQUET = <DownloadTickersFormat.PARQUET: 'parquet'>
class EquityCurveMeta:
 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.
EquityCurveMeta( input_point_count: int, output_point_count: int, resampled: bool, differential: bool, out_mode: EquityCurveOutMode)
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.

input_point_count: int
output_point_count: int
resampled: bool
differential: bool
out_mode: EquityCurveOutMode
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
89    @property
90    def additional_keys(self) -> list[str]:
91        return list(self.additional_properties.keys())
class EquityCurveOptions:
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.
EquityCurveOptions( resample: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, differential: bool | qtsurfer.api.client._generated.types.Unset = False, out_mode: EquityCurveOutMode | qtsurfer.api.client._generated.types.Unset = <EquityCurveOutMode.ARRAY: '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.

resample: int | qtsurfer.api.client._generated.types.Unset
differential: bool | qtsurfer.api.client._generated.types.Unset
out_mode: EquityCurveOutMode | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
83    @property
84    def additional_keys(self) -> list[str]:
85        return list(self.additional_properties.keys())
class EquityCurveOutMode(builtins.str, enum.Enum):
 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'.

ARRAY = <EquityCurveOutMode.ARRAY: 'ARRAY'>
SHORT = <EquityCurveOutMode.SHORT: 'SHORT'>
class EquityCurveRequest:
 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.
EquityCurveRequest( resample: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, differential: bool | qtsurfer.api.client._generated.types.Unset = False, out_mode: EquityCurveOutMode | qtsurfer.api.client._generated.types.Unset = <EquityCurveOutMode.ARRAY: 'ARRAY'>, mode: EquityCurveRequestMode | qtsurfer.api.client._generated.types.Unset = <EquityCurveRequestMode.AUTO: 'auto'>, n: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, max_pct: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

resample: int | qtsurfer.api.client._generated.types.Unset
differential: bool | qtsurfer.api.client._generated.types.Unset
out_mode: EquityCurveOutMode | qtsurfer.api.client._generated.types.Unset
mode: EquityCurveRequestMode | qtsurfer.api.client._generated.types.Unset
n: int | qtsurfer.api.client._generated.types.Unset
max_pct: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
120    @property
121    def additional_keys(self) -> list[str]:
122        return list(self.additional_properties.keys())
class EquityCurveRequestMode(builtins.str, enum.Enum):
 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'.

AUTO = <EquityCurveRequestMode.AUTO: 'auto'>
NONE = <EquityCurveRequestMode.NONE: 'none'>
TOPN = <EquityCurveRequestMode.TOPN: 'topN'>
TOPPCT = <EquityCurveRequestMode.TOPPCT: 'topPct'>
class EquityCurveResult:
 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.
EquityCurveResult( meta: EquityCurveMeta, points: list[EquityPoint] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, timestamps: list[int] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, equities: list[float] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, url: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

points: list[EquityPoint] | qtsurfer.api.client._generated.types.Unset
timestamps: list[int] | qtsurfer.api.client._generated.types.Unset
equities: list[float] | qtsurfer.api.client._generated.types.Unset
url: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
122    @property
123    def additional_keys(self) -> list[str]:
124        return list(self.additional_properties.keys())
class EquityPoint:
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.

EquityPoint(timestamp: int, equity: float)
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.

timestamp: int
equity: float
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
58    @property
59    def additional_keys(self) -> list[str]:
60        return list(self.additional_properties.keys())
class Exchange:
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.

Exchange( id: str, name: str, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

id: str
name: str
description: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
68    @property
69    def additional_keys(self) -> list[str]:
70        return list(self.additional_properties.keys())
class ExecuteBacktestBody:
 21@_attrs_define
 22class ExecuteBacktestBody:
 23    """
 24    Attributes:
 25        prepare_job_id (str): Job ID returned by `POST /prepare` (must be in `Completed` state) Example:
 26            13RBLGQlPnfDjO6wyKSX8i.
 27        strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
 28            always yields the same id, for every caller. How much formatting the id ignores depends on
 29            the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 30            not.
 31             Example: 6bsh31ikwkuivhtgcoa6s4.
 32        store_signals (bool | Unset): When true, the worker uploads emitted signals to object storage and the
 33            response includes `signalsUrl` / `signalsId` fields. Defaults to false.
 34             Default: False.
 35        equity_curve (EquityCurveOptions | Unset): Requested equity-curve transform, applied server-side in a fixed
 36            pipeline order: `resample` (point count) then `differential` (encoding) then `outMode` (JSON shape) — each stage
 37            assumes the previous one already ran. A server-side size guard can still force a smaller/deflated shape above
 38            its thresholds regardless of what is requested here — see `EquityCurveMeta` for what actually happened.
 39        base_config (SweepBaseConfig | Unset):
 40        params (ExecuteBacktestBodyParams | Unset): Strategy properties to apply to this run. Omit to run the strategy's
 41            declared
 42            defaults, which is exactly what a request without this field has always done.
 43
 44            Each key is the `name` declared on the strategy's `@StrategyProperty`, which
 45            need NOT match the Java field it annotates — `GET`/`POST /strategy` returns
 46            `declaredProperties` for precisely this. A key naming no declared property is
 47            rejected: the job fails with the list of names the strategy does declare,
 48            rather than completing at the defaults and handing back a plausible result for
 49            parameters nobody chose.
 50
 51            Scalars only — number, string or boolean. Ranges and lists belong to
 52            `executeSweep`; one request here is one run. `null` is not a value: leave the
 53            key out to keep a property at its default. Keys are made of letters, digits,
 54            `_`, `-` and dots, and may not be `strategyId`, `storeSignals`, `equityCurve`,
 55            `backtestEnabled` or `backtestFakeExecution` — those configure the job rather
 56            than the strategy.
 57             Example: {'ema.fast.period': 9, 'ema.slow.period': 21, 'risk.pct': 0.5}.
 58    """
 59
 60    prepare_job_id: str
 61    strategy_id: str
 62    store_signals: bool | Unset = False
 63    equity_curve: EquityCurveOptions | Unset = UNSET
 64    base_config: SweepBaseConfig | Unset = UNSET
 65    params: ExecuteBacktestBodyParams | Unset = UNSET
 66    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 67
 68    def to_dict(self) -> dict[str, Any]:
 69        prepare_job_id = self.prepare_job_id
 70
 71        strategy_id = self.strategy_id
 72
 73        store_signals = self.store_signals
 74
 75        equity_curve: dict[str, Any] | Unset = UNSET
 76        if not isinstance(self.equity_curve, Unset):
 77            equity_curve = self.equity_curve.to_dict()
 78
 79        base_config: dict[str, Any] | Unset = UNSET
 80        if not isinstance(self.base_config, Unset):
 81            base_config = self.base_config.to_dict()
 82
 83        params: dict[str, Any] | Unset = UNSET
 84        if not isinstance(self.params, Unset):
 85            params = self.params.to_dict()
 86
 87        field_dict: dict[str, Any] = {}
 88        field_dict.update(self.additional_properties)
 89        field_dict.update(
 90            {
 91                "prepareJobId": prepare_job_id,
 92                "strategyId": strategy_id,
 93            }
 94        )
 95        if store_signals is not UNSET:
 96            field_dict["storeSignals"] = store_signals
 97        if equity_curve is not UNSET:
 98            field_dict["equityCurve"] = equity_curve
 99        if base_config is not UNSET:
100            field_dict["baseConfig"] = base_config
101        if params is not UNSET:
102            field_dict["params"] = params
103
104        return field_dict
105
106    @classmethod
107    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
108        from ..models.equity_curve_options import EquityCurveOptions
109        from ..models.execute_backtest_body_params import ExecuteBacktestBodyParams
110        from ..models.sweep_base_config import SweepBaseConfig
111
112        d = dict(src_dict)
113        prepare_job_id = d.pop("prepareJobId")
114
115        strategy_id = d.pop("strategyId")
116
117        store_signals = d.pop("storeSignals", UNSET)
118
119        _equity_curve = d.pop("equityCurve", UNSET)
120        equity_curve: EquityCurveOptions | Unset
121        if isinstance(_equity_curve, Unset):
122            equity_curve = UNSET
123        else:
124            equity_curve = EquityCurveOptions.from_dict(_equity_curve)
125
126        _base_config = d.pop("baseConfig", UNSET)
127        base_config: SweepBaseConfig | Unset
128        if isinstance(_base_config, Unset):
129            base_config = UNSET
130        else:
131            base_config = SweepBaseConfig.from_dict(_base_config)
132
133        _params = d.pop("params", UNSET)
134        params: ExecuteBacktestBodyParams | Unset
135        if isinstance(_params, Unset):
136            params = UNSET
137        else:
138            params = ExecuteBacktestBodyParams.from_dict(_params)
139
140        execute_backtest_body = cls(
141            prepare_job_id=prepare_job_id,
142            strategy_id=strategy_id,
143            store_signals=store_signals,
144            equity_curve=equity_curve,
145            base_config=base_config,
146            params=params,
147        )
148
149        execute_backtest_body.additional_properties = d
150        return execute_backtest_body
151
152    @property
153    def additional_keys(self) -> list[str]:
154        return list(self.additional_properties.keys())
155
156    def __getitem__(self, key: str) -> Any:
157        return self.additional_properties[key]
158
159    def __setitem__(self, key: str, value: Any) -> None:
160        self.additional_properties[key] = value
161
162    def __delitem__(self, key: str) -> None:
163        del self.additional_properties[key]
164
165    def __contains__(self, key: str) -> bool:
166        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. How much formatting the id ignores depends on the language — 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. base_config (SweepBaseConfig | Unset): params (ExecuteBacktestBodyParams | Unset): Strategy properties to apply to this run. Omit to run the strategy's declared defaults, which is exactly what a request without this field has always done.

    Each key is the `name` declared on the strategy's `@StrategyProperty`, which
    need NOT match the Java field it annotates — `GET`/`POST /strategy` returns
    `declaredProperties` for precisely this. A key naming no declared property is
    rejected: the job fails with the list of names the strategy does declare,
    rather than completing at the defaults and handing back a plausible result for
    parameters nobody chose.

    Scalars only — number, string or boolean. Ranges and lists belong to
    `executeSweep`; one request here is one run. `null` is not a value: leave the
    key out to keep a property at its default. Keys are made of letters, digits,
    `_`, `-` and dots, and may not be `strategyId`, `storeSignals`, `equityCurve`,
    `backtestEnabled` or `backtestFakeExecution` — those configure the job rather
    than the strategy.
     Example: {'ema.fast.period': 9, 'ema.slow.period': 21, 'risk.pct': 0.5}.
ExecuteBacktestBody( prepare_job_id: str, strategy_id: str, store_signals: bool | qtsurfer.api.client._generated.types.Unset = False, equity_curve: EquityCurveOptions | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, base_config: SweepBaseConfig | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, params: ExecuteBacktestBodyParams | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
29def __init__(self, prepare_job_id, strategy_id, store_signals=attr_dict['store_signals'].default, equity_curve=attr_dict['equity_curve'].default, base_config=attr_dict['base_config'].default, params=attr_dict['params'].default):
30    self.prepare_job_id = prepare_job_id
31    self.strategy_id = strategy_id
32    self.store_signals = store_signals
33    self.equity_curve = equity_curve
34    self.base_config = base_config
35    self.params = params
36    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class ExecuteBacktestBody.

prepare_job_id: str
strategy_id: str
store_signals: bool | qtsurfer.api.client._generated.types.Unset
equity_curve: EquityCurveOptions | qtsurfer.api.client._generated.types.Unset
base_config: SweepBaseConfig | qtsurfer.api.client._generated.types.Unset
params: ExecuteBacktestBodyParams | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 68    def to_dict(self) -> dict[str, Any]:
 69        prepare_job_id = self.prepare_job_id
 70
 71        strategy_id = self.strategy_id
 72
 73        store_signals = self.store_signals
 74
 75        equity_curve: dict[str, Any] | Unset = UNSET
 76        if not isinstance(self.equity_curve, Unset):
 77            equity_curve = self.equity_curve.to_dict()
 78
 79        base_config: dict[str, Any] | Unset = UNSET
 80        if not isinstance(self.base_config, Unset):
 81            base_config = self.base_config.to_dict()
 82
 83        params: dict[str, Any] | Unset = UNSET
 84        if not isinstance(self.params, Unset):
 85            params = self.params.to_dict()
 86
 87        field_dict: dict[str, Any] = {}
 88        field_dict.update(self.additional_properties)
 89        field_dict.update(
 90            {
 91                "prepareJobId": prepare_job_id,
 92                "strategyId": strategy_id,
 93            }
 94        )
 95        if store_signals is not UNSET:
 96            field_dict["storeSignals"] = store_signals
 97        if equity_curve is not UNSET:
 98            field_dict["equityCurve"] = equity_curve
 99        if base_config is not UNSET:
100            field_dict["baseConfig"] = base_config
101        if params is not UNSET:
102            field_dict["params"] = params
103
104        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
106    @classmethod
107    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
108        from ..models.equity_curve_options import EquityCurveOptions
109        from ..models.execute_backtest_body_params import ExecuteBacktestBodyParams
110        from ..models.sweep_base_config import SweepBaseConfig
111
112        d = dict(src_dict)
113        prepare_job_id = d.pop("prepareJobId")
114
115        strategy_id = d.pop("strategyId")
116
117        store_signals = d.pop("storeSignals", UNSET)
118
119        _equity_curve = d.pop("equityCurve", UNSET)
120        equity_curve: EquityCurveOptions | Unset
121        if isinstance(_equity_curve, Unset):
122            equity_curve = UNSET
123        else:
124            equity_curve = EquityCurveOptions.from_dict(_equity_curve)
125
126        _base_config = d.pop("baseConfig", UNSET)
127        base_config: SweepBaseConfig | Unset
128        if isinstance(_base_config, Unset):
129            base_config = UNSET
130        else:
131            base_config = SweepBaseConfig.from_dict(_base_config)
132
133        _params = d.pop("params", UNSET)
134        params: ExecuteBacktestBodyParams | Unset
135        if isinstance(_params, Unset):
136            params = UNSET
137        else:
138            params = ExecuteBacktestBodyParams.from_dict(_params)
139
140        execute_backtest_body = cls(
141            prepare_job_id=prepare_job_id,
142            strategy_id=strategy_id,
143            store_signals=store_signals,
144            equity_curve=equity_curve,
145            base_config=base_config,
146            params=params,
147        )
148
149        execute_backtest_body.additional_properties = d
150        return execute_backtest_body
additional_keys: list[str]
152    @property
153    def additional_keys(self) -> list[str]:
154        return list(self.additional_properties.keys())
class ExecuteBacktestBodyParams:
13@_attrs_define
14class ExecuteBacktestBodyParams:
15    """Strategy properties to apply to this run. Omit to run the strategy's declared
16    defaults, which is exactly what a request without this field has always done.
17
18    Each key is the `name` declared on the strategy's `@StrategyProperty`, which
19    need NOT match the Java field it annotates — `GET`/`POST /strategy` returns
20    `declaredProperties` for precisely this. A key naming no declared property is
21    rejected: the job fails with the list of names the strategy does declare,
22    rather than completing at the defaults and handing back a plausible result for
23    parameters nobody chose.
24
25    Scalars only — number, string or boolean. Ranges and lists belong to
26    `executeSweep`; one request here is one run. `null` is not a value: leave the
27    key out to keep a property at its default. Keys are made of letters, digits,
28    `_`, `-` and dots, and may not be `strategyId`, `storeSignals`, `equityCurve`,
29    `backtestEnabled` or `backtestFakeExecution` — those configure the job rather
30    than the strategy.
31
32        Example:
33            {'ema.fast.period': 9, 'ema.slow.period': 21, 'risk.pct': 0.5}
34
35    """
36
37    additional_properties: dict[str, bool | float | str] = _attrs_field(init=False, factory=dict)
38
39    def to_dict(self) -> dict[str, Any]:
40
41        field_dict: dict[str, Any] = {}
42        for prop_name, prop in self.additional_properties.items():
43            field_dict[prop_name] = prop
44
45        return field_dict
46
47    @classmethod
48    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
49        d = dict(src_dict)
50        execute_backtest_body_params = cls()
51
52        additional_properties = {}
53        for prop_name, prop_dict in d.items():
54
55            def _parse_additional_property(data: object) -> bool | float | str:
56                return cast(bool | float | str, data)
57
58            additional_property = _parse_additional_property(prop_dict)
59
60            additional_properties[prop_name] = additional_property
61
62        execute_backtest_body_params.additional_properties = additional_properties
63        return execute_backtest_body_params
64
65    @property
66    def additional_keys(self) -> list[str]:
67        return list(self.additional_properties.keys())
68
69    def __getitem__(self, key: str) -> bool | float | str:
70        return self.additional_properties[key]
71
72    def __setitem__(self, key: str, value: bool | float | str) -> 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

Strategy properties to apply to this run. Omit to run the strategy's declared defaults, which is exactly what a request without this field has always done.

Each key is the name declared on the strategy's @StrategyProperty, which need NOT match the Java field it annotates — GET/POST /strategy returns declaredProperties for precisely this. A key naming no declared property is rejected: the job fails with the list of names the strategy does declare, rather than completing at the defaults and handing back a plausible result for parameters nobody chose.

Scalars only — number, string or boolean. Ranges and lists belong to executeSweep; one request here is one run. null is not a value: leave the key out to keep a property at its default. Keys are made of letters, digits, _, - and dots, and may not be strategyId, storeSignals, equityCurve, backtestEnabled or backtestFakeExecution — those configure the job rather than the strategy.

Example:
    {'ema.fast.period': 9, 'ema.slow.period': 21, 'risk.pct': 0.5}
ExecuteBacktestBodyParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class ExecuteBacktestBodyParams.

additional_properties: dict[str, bool | float | str]
def to_dict(self) -> dict[str, typing.Any]:
39    def to_dict(self) -> dict[str, Any]:
40
41        field_dict: dict[str, Any] = {}
42        for prop_name, prop in self.additional_properties.items():
43            field_dict[prop_name] = prop
44
45        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
47    @classmethod
48    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
49        d = dict(src_dict)
50        execute_backtest_body_params = cls()
51
52        additional_properties = {}
53        for prop_name, prop_dict in d.items():
54
55            def _parse_additional_property(data: object) -> bool | float | str:
56                return cast(bool | float | str, data)
57
58            additional_property = _parse_additional_property(prop_dict)
59
60            additional_properties[prop_name] = additional_property
61
62        execute_backtest_body_params.additional_properties = additional_properties
63        return execute_backtest_body_params
additional_keys: list[str]
65    @property
66    def additional_keys(self) -> list[str]:
67        return list(self.additional_properties.keys())
class ExecuteSweepAccepted:
 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.

ExecuteSweepAccepted( sweep_id: str, request_id: str, total_runs: int, shards: int, seed: int, queued: bool, walk_forward: WalkForwardAccepted | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

sweep_id: str
request_id: str
total_runs: int
shards: int
seed: int
queued: bool
walk_forward: WalkForwardAccepted | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
113    @property
114    def additional_keys(self) -> list[str]:
115        return list(self.additional_properties.keys())
class ExecuteSweepRequest:
 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. How much formatting the id ignores depends on
 28            the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 29            not.
 30             Example: 6bsh31ikwkuivhtgcoa6s4.
 31        sweep (SweepSpecRequest):  Example: {'sampler': 'lhs', 'seed': 487221, 'samples': 100, 'objective': 'sharpe',
 32            'params': {'rsiPeriod': {'from': 7, 'to': 28, 'step': 1}, 'useTrendFilter': {'values': [True, False]}}}.
 33        base_config (SweepBaseConfig | Unset):
 34        store_signals (bool | Unset): Store signals for every trial. Keep false for normal sweeps. Default: False.
 35        shards (int | Unset): Requested horizontal shard count; 0 or omitted selects automatically. Default: 0.
 36        min_trade_floor (int | Unset): Trials below this trade count are flagged but remain in the results. Default: 30.
 37        walk_forward (WalkForwardRequest | Unset): Opt in to walk-forward validation. Present, the sweep runs as F
 38            sequential folds and the result gains a `walkForward` section; absent, nothing about the sweep changes. Two
 39            requests that differ only in this block are two different sweeps and do not deduplicate against each other.
 40        equity_curve (EquityCurveRequest | Unset): Selection (`mode`/`n`/`maxPct`) plus the transform preference
 41            (`resample`/`differential`/`outMode`) applied by `GET .../equityCurve` whenever ITS OWN query params are absent,
 42            for a curve this sweep retained. The transform half never affects retention or `sweepId` — a caller can always
 43            override it per-request at read time regardless of what was submitted here.
 44    """
 45
 46    strategy_id: str
 47    sweep: SweepSpecRequest
 48    base_config: SweepBaseConfig | Unset = UNSET
 49    store_signals: bool | Unset = False
 50    shards: int | Unset = 0
 51    min_trade_floor: int | Unset = 30
 52    walk_forward: WalkForwardRequest | Unset = UNSET
 53    equity_curve: EquityCurveRequest | Unset = UNSET
 54    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 55
 56    def to_dict(self) -> dict[str, Any]:
 57        strategy_id = self.strategy_id
 58
 59        sweep = self.sweep.to_dict()
 60
 61        base_config: dict[str, Any] | Unset = UNSET
 62        if not isinstance(self.base_config, Unset):
 63            base_config = self.base_config.to_dict()
 64
 65        store_signals = self.store_signals
 66
 67        shards = self.shards
 68
 69        min_trade_floor = self.min_trade_floor
 70
 71        walk_forward: dict[str, Any] | Unset = UNSET
 72        if not isinstance(self.walk_forward, Unset):
 73            walk_forward = self.walk_forward.to_dict()
 74
 75        equity_curve: dict[str, Any] | Unset = UNSET
 76        if not isinstance(self.equity_curve, Unset):
 77            equity_curve = self.equity_curve.to_dict()
 78
 79        field_dict: dict[str, Any] = {}
 80        field_dict.update(self.additional_properties)
 81        field_dict.update(
 82            {
 83                "strategyId": strategy_id,
 84                "sweep": sweep,
 85            }
 86        )
 87        if base_config is not UNSET:
 88            field_dict["baseConfig"] = base_config
 89        if store_signals is not UNSET:
 90            field_dict["storeSignals"] = store_signals
 91        if shards is not UNSET:
 92            field_dict["shards"] = shards
 93        if min_trade_floor is not UNSET:
 94            field_dict["minTradeFloor"] = min_trade_floor
 95        if walk_forward is not UNSET:
 96            field_dict["walkForward"] = walk_forward
 97        if equity_curve is not UNSET:
 98            field_dict["equityCurve"] = equity_curve
 99
100        return field_dict
101
102    @classmethod
103    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
104        from ..models.equity_curve_request import EquityCurveRequest
105        from ..models.sweep_base_config import SweepBaseConfig
106        from ..models.sweep_spec_request import SweepSpecRequest
107        from ..models.walk_forward_request import WalkForwardRequest
108
109        d = dict(src_dict)
110        strategy_id = d.pop("strategyId")
111
112        sweep = SweepSpecRequest.from_dict(d.pop("sweep"))
113
114        _base_config = d.pop("baseConfig", UNSET)
115        base_config: SweepBaseConfig | Unset
116        if isinstance(_base_config, Unset):
117            base_config = UNSET
118        else:
119            base_config = SweepBaseConfig.from_dict(_base_config)
120
121        store_signals = d.pop("storeSignals", UNSET)
122
123        shards = d.pop("shards", UNSET)
124
125        min_trade_floor = d.pop("minTradeFloor", UNSET)
126
127        _walk_forward = d.pop("walkForward", UNSET)
128        walk_forward: WalkForwardRequest | Unset
129        if isinstance(_walk_forward, Unset):
130            walk_forward = UNSET
131        else:
132            walk_forward = WalkForwardRequest.from_dict(_walk_forward)
133
134        _equity_curve = d.pop("equityCurve", UNSET)
135        equity_curve: EquityCurveRequest | Unset
136        if isinstance(_equity_curve, Unset):
137            equity_curve = UNSET
138        else:
139            equity_curve = EquityCurveRequest.from_dict(_equity_curve)
140
141        execute_sweep_request = cls(
142            strategy_id=strategy_id,
143            sweep=sweep,
144            base_config=base_config,
145            store_signals=store_signals,
146            shards=shards,
147            min_trade_floor=min_trade_floor,
148            walk_forward=walk_forward,
149            equity_curve=equity_curve,
150        )
151
152        execute_sweep_request.additional_properties = d
153        return execute_sweep_request
154
155    @property
156    def additional_keys(self) -> list[str]:
157        return list(self.additional_properties.keys())
158
159    def __getitem__(self, key: str) -> Any:
160        return self.additional_properties[key]
161
162    def __setitem__(self, key: str, value: Any) -> None:
163        self.additional_properties[key] = value
164
165    def __delitem__(self, key: str) -> None:
166        del self.additional_properties[key]
167
168    def __contains__(self, key: str) -> bool:
169        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. How much formatting the id ignores depends on the language — 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.

ExecuteSweepRequest( strategy_id: str, sweep: SweepSpecRequest, base_config: SweepBaseConfig | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, store_signals: bool | qtsurfer.api.client._generated.types.Unset = False, shards: int | qtsurfer.api.client._generated.types.Unset = 0, min_trade_floor: int | qtsurfer.api.client._generated.types.Unset = 30, walk_forward: WalkForwardRequest | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, equity_curve: EquityCurveRequest | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

strategy_id: str
base_config: SweepBaseConfig | qtsurfer.api.client._generated.types.Unset
store_signals: bool | qtsurfer.api.client._generated.types.Unset
shards: int | qtsurfer.api.client._generated.types.Unset
min_trade_floor: int | qtsurfer.api.client._generated.types.Unset
walk_forward: WalkForwardRequest | qtsurfer.api.client._generated.types.Unset
equity_curve: EquityCurveRequest | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 56    def to_dict(self) -> dict[str, Any]:
 57        strategy_id = self.strategy_id
 58
 59        sweep = self.sweep.to_dict()
 60
 61        base_config: dict[str, Any] | Unset = UNSET
 62        if not isinstance(self.base_config, Unset):
 63            base_config = self.base_config.to_dict()
 64
 65        store_signals = self.store_signals
 66
 67        shards = self.shards
 68
 69        min_trade_floor = self.min_trade_floor
 70
 71        walk_forward: dict[str, Any] | Unset = UNSET
 72        if not isinstance(self.walk_forward, Unset):
 73            walk_forward = self.walk_forward.to_dict()
 74
 75        equity_curve: dict[str, Any] | Unset = UNSET
 76        if not isinstance(self.equity_curve, Unset):
 77            equity_curve = self.equity_curve.to_dict()
 78
 79        field_dict: dict[str, Any] = {}
 80        field_dict.update(self.additional_properties)
 81        field_dict.update(
 82            {
 83                "strategyId": strategy_id,
 84                "sweep": sweep,
 85            }
 86        )
 87        if base_config is not UNSET:
 88            field_dict["baseConfig"] = base_config
 89        if store_signals is not UNSET:
 90            field_dict["storeSignals"] = store_signals
 91        if shards is not UNSET:
 92            field_dict["shards"] = shards
 93        if min_trade_floor is not UNSET:
 94            field_dict["minTradeFloor"] = min_trade_floor
 95        if walk_forward is not UNSET:
 96            field_dict["walkForward"] = walk_forward
 97        if equity_curve is not UNSET:
 98            field_dict["equityCurve"] = equity_curve
 99
100        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
102    @classmethod
103    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
104        from ..models.equity_curve_request import EquityCurveRequest
105        from ..models.sweep_base_config import SweepBaseConfig
106        from ..models.sweep_spec_request import SweepSpecRequest
107        from ..models.walk_forward_request import WalkForwardRequest
108
109        d = dict(src_dict)
110        strategy_id = d.pop("strategyId")
111
112        sweep = SweepSpecRequest.from_dict(d.pop("sweep"))
113
114        _base_config = d.pop("baseConfig", UNSET)
115        base_config: SweepBaseConfig | Unset
116        if isinstance(_base_config, Unset):
117            base_config = UNSET
118        else:
119            base_config = SweepBaseConfig.from_dict(_base_config)
120
121        store_signals = d.pop("storeSignals", UNSET)
122
123        shards = d.pop("shards", UNSET)
124
125        min_trade_floor = d.pop("minTradeFloor", UNSET)
126
127        _walk_forward = d.pop("walkForward", UNSET)
128        walk_forward: WalkForwardRequest | Unset
129        if isinstance(_walk_forward, Unset):
130            walk_forward = UNSET
131        else:
132            walk_forward = WalkForwardRequest.from_dict(_walk_forward)
133
134        _equity_curve = d.pop("equityCurve", UNSET)
135        equity_curve: EquityCurveRequest | Unset
136        if isinstance(_equity_curve, Unset):
137            equity_curve = UNSET
138        else:
139            equity_curve = EquityCurveRequest.from_dict(_equity_curve)
140
141        execute_sweep_request = cls(
142            strategy_id=strategy_id,
143            sweep=sweep,
144            base_config=base_config,
145            store_signals=store_signals,
146            shards=shards,
147            min_trade_floor=min_trade_floor,
148            walk_forward=walk_forward,
149            equity_curve=equity_curve,
150        )
151
152        execute_sweep_request.additional_properties = d
153        return execute_sweep_request
additional_keys: list[str]
155    @property
156    def additional_keys(self) -> list[str]:
157        return list(self.additional_properties.keys())
class ExecuteSweepResult:
 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.

ExecuteSweepResult( sweep_id: str, status: ExecuteSweepResultStatus, objective: ExecuteSweepResultObjective, order: ExecuteSweepResultOrder, progress: SweepProgress, leaderboard_size: int, truncated: bool, leaderboard: list[SweepRunRow], state: JobState, ranking: ExecuteSweepResultRanking | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, pbo: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, pbo_splits: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, fail_reason: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, walk_forward: WalkForwardResult | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

sweep_id: str
progress: SweepProgress
leaderboard_size: int
truncated: bool
leaderboard: list[SweepRunRow]
state: JobState
ranking: ExecuteSweepResultRanking | qtsurfer.api.client._generated.types.Unset
pbo: float | qtsurfer.api.client._generated.types.Unset
pbo_splits: int | qtsurfer.api.client._generated.types.Unset
fail_reason: str | qtsurfer.api.client._generated.types.Unset
walk_forward: WalkForwardResult | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
214    @property
215    def additional_keys(self) -> list[str]:
216        return list(self.additional_properties.keys())
class ExecuteSweepResultObjective(builtins.str, enum.Enum):
 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'.

SHARPE = <ExecuteSweepResultObjective.SHARPE: 'sharpe'>
SORTINO = <ExecuteSweepResultObjective.SORTINO: 'sortino'>
class ExecuteSweepResultOrder(builtins.str, enum.Enum):
 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'.

NATURAL = <ExecuteSweepResultOrder.NATURAL: 'natural'>
RANKED = <ExecuteSweepResultOrder.RANKED: 'ranked'>
class ExecuteSweepResultRanking(builtins.str, enum.Enum):
 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'.

PLATEAU = <ExecuteSweepResultRanking.PLATEAU: 'plateau'>
class ExecuteSweepResultStatus(builtins.str, enum.Enum):
 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'.

CANCELLED = <ExecuteSweepResultStatus.CANCELLED: 'CANCELLED'>
COMPLETED = <ExecuteSweepResultStatus.COMPLETED: 'COMPLETED'>
PARTIAL = <ExecuteSweepResultStatus.PARTIAL: 'PARTIAL'>
RUNNING = <ExecuteSweepResultStatus.RUNNING: 'RUNNING'>
class FinalizeDatasetUploadResponse202:
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):

FinalizeDatasetUploadResponse202(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.

job_id: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
48    @property
49    def additional_keys(self) -> list[str]:
50        return list(self.additional_properties.keys())
class GetBacktestResultResponse202:
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
GetBacktestResultResponse202()
21def __init__(self, ):
22    pass

Method generated by attrs for class GetBacktestResultResponse202.

def to_dict(self) -> dict[str, typing.Any]:
16    def to_dict(self) -> dict[str, Any]:
17
18        field_dict: dict[str, Any] = {}
19
20        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
class GetStrategyCodeResponse200:
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. How much formatting the id ignores depends on
19            the language — see `POST /strategy` for exactly which rewrites preserve it and which do
20            not.
21             Example: 6bsh31ikwkuivhtgcoa6s4.
22        code (str): Raw strategy source code (Java or QTScript), exactly as registered.
23    """
24
25    strategy_id: str
26    code: str
27    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
29    def to_dict(self) -> dict[str, Any]:
30        strategy_id = self.strategy_id
31
32        code = self.code
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "strategyId": strategy_id,
39                "code": code,
40            }
41        )
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        strategy_id = d.pop("strategyId")
49
50        code = d.pop("code")
51
52        get_strategy_code_response_200 = cls(
53            strategy_id=strategy_id,
54            code=code,
55        )
56
57        get_strategy_code_response_200.additional_properties = d
58        return get_strategy_code_response_200
59
60    @property
61    def additional_keys(self) -> list[str]:
62        return list(self.additional_properties.keys())
63
64    def __getitem__(self, key: str) -> Any:
65        return self.additional_properties[key]
66
67    def __setitem__(self, key: str, value: Any) -> None:
68        self.additional_properties[key] = value
69
70    def __delitem__(self, key: str) -> None:
71        del self.additional_properties[key]
72
73    def __contains__(self, key: str) -> bool:
74        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. How much formatting the id ignores depends on the language — see POST /strategy for exactly which rewrites preserve it and which do not. Example: 6bsh31ikwkuivhtgcoa6s4. code (str): Raw strategy source code (Java or QTScript), exactly as registered.

GetStrategyCodeResponse200(strategy_id: str, code: str)
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.

strategy_id: str
code: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
29    def to_dict(self) -> dict[str, Any]:
30        strategy_id = self.strategy_id
31
32        code = self.code
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "strategyId": strategy_id,
39                "code": code,
40            }
41        )
42
43        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
45    @classmethod
46    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
47        d = dict(src_dict)
48        strategy_id = d.pop("strategyId")
49
50        code = d.pop("code")
51
52        get_strategy_code_response_200 = cls(
53            strategy_id=strategy_id,
54            code=code,
55        )
56
57        get_strategy_code_response_200.additional_properties = d
58        return get_strategy_code_response_200
additional_keys: list[str]
60    @property
61    def additional_keys(self) -> list[str]:
62        return list(self.additional_properties.keys())
class GetSweepResultObjective(builtins.str, enum.Enum):
 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'.

MAXDD = <GetSweepResultObjective.MAXDD: 'maxdd'>
SHARPE = <GetSweepResultObjective.SHARPE: 'sharpe'>
SORTINO = <GetSweepResultObjective.SORTINO: 'sortino'>
class GetSweepResultOrder(builtins.str, enum.Enum):
 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'.

NATURAL = <GetSweepResultOrder.NATURAL: 'natural'>
RANKED = <GetSweepResultOrder.RANKED: 'ranked'>
class GetSweepResultRanking(builtins.str, enum.Enum):
 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'.

PLATEAU = <GetSweepResultRanking.PLATEAU: 'plateau'>
RAW = <GetSweepResultRanking.RAW: 'raw'>
class GetSweepSensitivityObjective(builtins.str, enum.Enum):
 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'.

SORTINO = <GetSweepSensitivityObjective.SORTINO: 'sortino'>
class InstrumentCoverage:
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

InstrumentCoverage( tickers: CoverageWindow | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, klines: CoverageWindow | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

tickers: CoverageWindow | qtsurfer.api.client._generated.types.Unset
klines: CoverageWindow | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
78    @property
79    def additional_keys(self) -> list[str]:
80        return list(self.additional_properties.keys())
class InstrumentDetail:
 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.

InstrumentDetail( id: str, base: str, quote: str, coverage: InstrumentCoverage | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, last_price: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, volume24h: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

id: str
base: str
quote: str
coverage: InstrumentCoverage | qtsurfer.api.client._generated.types.Unset
last_price: float | qtsurfer.api.client._generated.types.Unset
volume24h: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
107    @property
108    def additional_keys(self) -> list[str]:
109        return list(self.additional_properties.keys())
class InstrumentListMeta:
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.

InstrumentListMeta( updated_at: datetime.datetime, exchange: str, segment: InstrumentListMetaSegment)
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.

updated_at: datetime.datetime
exchange: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
69    @property
70    def additional_keys(self) -> list[str]:
71        return list(self.additional_properties.keys())
class InstrumentListMetaSegment(builtins.str, enum.Enum):
 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'.

FUTURES = <InstrumentListMetaSegment.FUTURES: 'futures'>
class InstrumentListResponse:
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

InstrumentListResponse( data: list[InstrumentDetail], meta: InstrumentListMeta, field_links: InstrumentLinks)
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.

data: list[InstrumentDetail]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
83    @property
84    def additional_keys(self) -> list[str]:
85        return list(self.additional_properties.keys())
class JobState:
 18@_attrs_define
 19class JobState:
 20    """Information about a single job
 21
 22    Attributes:
 23        context_id (str): Identifier for the job's execution context. Its current shape is a colon-delimited string
 24            encoding the data source type, an internal user id, the exchange, the job id, and the instrument — but that
 25            structure is not a committed contract and may change without notice. Treat it as an opaque token: store and pass
 26            it back, don't parse it. Example:
 27            jctx:ticker:00000000-0000-0000-0000-000000000000:binance:5ikyamio8b3v9wcnfxztzg:btc/usdt:0vicnz3thzhrqvfczks1pu.
 28        status (JobStateStatus): Current status of the job. Treat `Completed | Aborted | Failed` as
 29            terminal; `New | Started` mean keep polling. A single-instrument prepare
 30            is always terminal (`Completed`) — decide from
 31            `PrepareJobState.coverageRatio` (or `dataFrom`/`dataTo` against an `rt` dataset,
 32            which has no ratio), not by polling.
 33             Example: Completed.
 34        size (int): Total size of the data being prepared Example: 100.
 35        completed (int): The amount of data processed so far Example: 50.
 36        status_detail (None | str | Unset): Detailed status information, if available Example: Job completed with error
 37            code 5001.
 38        start_time (datetime.datetime | None | Unset): Timestamp for when the preparation started Example:
 39            2025-01-04T14:00:00Z.
 40        end_time (datetime.datetime | None | Unset): Timestamp for when the preparation finished Example:
 41            2025-01-04T14:00:20Z.
 42    """
 43
 44    context_id: str
 45    status: JobStateStatus
 46    size: int
 47    completed: int
 48    status_detail: None | str | Unset = UNSET
 49    start_time: datetime.datetime | None | Unset = UNSET
 50    end_time: datetime.datetime | None | Unset = UNSET
 51    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 52
 53    def to_dict(self) -> dict[str, Any]:
 54        context_id = self.context_id
 55
 56        status = self.status.value
 57
 58        size = self.size
 59
 60        completed = self.completed
 61
 62        status_detail: None | str | Unset
 63        if isinstance(self.status_detail, Unset):
 64            status_detail = UNSET
 65        else:
 66            status_detail = self.status_detail
 67
 68        start_time: None | str | Unset
 69        if isinstance(self.start_time, Unset):
 70            start_time = UNSET
 71        elif isinstance(self.start_time, datetime.datetime):
 72            start_time = self.start_time.isoformat()
 73        else:
 74            start_time = self.start_time
 75
 76        end_time: None | str | Unset
 77        if isinstance(self.end_time, Unset):
 78            end_time = UNSET
 79        elif isinstance(self.end_time, datetime.datetime):
 80            end_time = self.end_time.isoformat()
 81        else:
 82            end_time = self.end_time
 83
 84        field_dict: dict[str, Any] = {}
 85        field_dict.update(self.additional_properties)
 86        field_dict.update(
 87            {
 88                "contextId": context_id,
 89                "status": status,
 90                "size": size,
 91                "completed": completed,
 92            }
 93        )
 94        if status_detail is not UNSET:
 95            field_dict["statusDetail"] = status_detail
 96        if start_time is not UNSET:
 97            field_dict["startTime"] = start_time
 98        if end_time is not UNSET:
 99            field_dict["endTime"] = end_time
100
101        return field_dict
102
103    @classmethod
104    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
105        d = dict(src_dict)
106        context_id = d.pop("contextId")
107
108        status = JobStateStatus(d.pop("status"))
109
110        size = d.pop("size")
111
112        completed = d.pop("completed")
113
114        def _parse_status_detail(data: object) -> None | str | Unset:
115            if data is None:
116                return data
117            if isinstance(data, Unset):
118                return data
119            return cast(None | str | Unset, data)
120
121        status_detail = _parse_status_detail(d.pop("statusDetail", UNSET))
122
123        def _parse_start_time(data: object) -> datetime.datetime | None | Unset:
124            if data is None:
125                return data
126            if isinstance(data, Unset):
127                return data
128            try:
129                if not isinstance(data, str):
130                    raise TypeError()
131                start_time_type_0 = isoparse(data)
132
133                return start_time_type_0
134            except (TypeError, ValueError, AttributeError, KeyError):
135                pass
136            return cast(datetime.datetime | None | Unset, data)
137
138        start_time = _parse_start_time(d.pop("startTime", UNSET))
139
140        def _parse_end_time(data: object) -> datetime.datetime | None | Unset:
141            if data is None:
142                return data
143            if isinstance(data, Unset):
144                return data
145            try:
146                if not isinstance(data, str):
147                    raise TypeError()
148                end_time_type_0 = isoparse(data)
149
150                return end_time_type_0
151            except (TypeError, ValueError, AttributeError, KeyError):
152                pass
153            return cast(datetime.datetime | None | Unset, data)
154
155        end_time = _parse_end_time(d.pop("endTime", UNSET))
156
157        job_state = cls(
158            context_id=context_id,
159            status=status,
160            size=size,
161            completed=completed,
162            status_detail=status_detail,
163            start_time=start_time,
164            end_time=end_time,
165        )
166
167        job_state.additional_properties = d
168        return job_state
169
170    @property
171    def additional_keys(self) -> list[str]:
172        return list(self.additional_properties.keys())
173
174    def __getitem__(self, key: str) -> Any:
175        return self.additional_properties[key]
176
177    def __setitem__(self, key: str, value: Any) -> None:
178        self.additional_properties[key] = value
179
180    def __delitem__(self, key: str) -> None:
181        del self.additional_properties[key]
182
183    def __contains__(self, key: str) -> bool:
184        return key in self.additional_properties

Information about a single job

Attributes: context_id (str): Identifier for the job's execution context. Its current shape is a colon-delimited string encoding the data source type, an internal user id, the exchange, the job id, and the instrument — but that structure is not a committed contract and may change without notice. Treat it as an opaque token: store and pass it back, don't parse it. Example: jctx:ticker:00000000-0000-0000-0000-000000000000:binance:5ikyamio8b3v9wcnfxztzg:btc/usdt:0vicnz3thzhrqvfczks1pu. 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 (or dataFrom/dataTo against an rt dataset, which has no ratio), 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.

JobState( context_id: str, status: JobStateStatus, size: int, completed: int, status_detail: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, start_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, end_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

context_id: str
status: JobStateStatus
size: int
completed: int
status_detail: None | str | qtsurfer.api.client._generated.types.Unset
start_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset
end_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 53    def to_dict(self) -> dict[str, Any]:
 54        context_id = self.context_id
 55
 56        status = self.status.value
 57
 58        size = self.size
 59
 60        completed = self.completed
 61
 62        status_detail: None | str | Unset
 63        if isinstance(self.status_detail, Unset):
 64            status_detail = UNSET
 65        else:
 66            status_detail = self.status_detail
 67
 68        start_time: None | str | Unset
 69        if isinstance(self.start_time, Unset):
 70            start_time = UNSET
 71        elif isinstance(self.start_time, datetime.datetime):
 72            start_time = self.start_time.isoformat()
 73        else:
 74            start_time = self.start_time
 75
 76        end_time: None | str | Unset
 77        if isinstance(self.end_time, Unset):
 78            end_time = UNSET
 79        elif isinstance(self.end_time, datetime.datetime):
 80            end_time = self.end_time.isoformat()
 81        else:
 82            end_time = self.end_time
 83
 84        field_dict: dict[str, Any] = {}
 85        field_dict.update(self.additional_properties)
 86        field_dict.update(
 87            {
 88                "contextId": context_id,
 89                "status": status,
 90                "size": size,
 91                "completed": completed,
 92            }
 93        )
 94        if status_detail is not UNSET:
 95            field_dict["statusDetail"] = status_detail
 96        if start_time is not UNSET:
 97            field_dict["startTime"] = start_time
 98        if end_time is not UNSET:
 99            field_dict["endTime"] = end_time
100
101        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
103    @classmethod
104    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
105        d = dict(src_dict)
106        context_id = d.pop("contextId")
107
108        status = JobStateStatus(d.pop("status"))
109
110        size = d.pop("size")
111
112        completed = d.pop("completed")
113
114        def _parse_status_detail(data: object) -> None | str | Unset:
115            if data is None:
116                return data
117            if isinstance(data, Unset):
118                return data
119            return cast(None | str | Unset, data)
120
121        status_detail = _parse_status_detail(d.pop("statusDetail", UNSET))
122
123        def _parse_start_time(data: object) -> datetime.datetime | None | Unset:
124            if data is None:
125                return data
126            if isinstance(data, Unset):
127                return data
128            try:
129                if not isinstance(data, str):
130                    raise TypeError()
131                start_time_type_0 = isoparse(data)
132
133                return start_time_type_0
134            except (TypeError, ValueError, AttributeError, KeyError):
135                pass
136            return cast(datetime.datetime | None | Unset, data)
137
138        start_time = _parse_start_time(d.pop("startTime", UNSET))
139
140        def _parse_end_time(data: object) -> datetime.datetime | None | Unset:
141            if data is None:
142                return data
143            if isinstance(data, Unset):
144                return data
145            try:
146                if not isinstance(data, str):
147                    raise TypeError()
148                end_time_type_0 = isoparse(data)
149
150                return end_time_type_0
151            except (TypeError, ValueError, AttributeError, KeyError):
152                pass
153            return cast(datetime.datetime | None | Unset, data)
154
155        end_time = _parse_end_time(d.pop("endTime", UNSET))
156
157        job_state = cls(
158            context_id=context_id,
159            status=status,
160            size=size,
161            completed=completed,
162            status_detail=status_detail,
163            start_time=start_time,
164            end_time=end_time,
165        )
166
167        job_state.additional_properties = d
168        return job_state
additional_keys: list[str]
170    @property
171    def additional_keys(self) -> list[str]:
172        return list(self.additional_properties.keys())
class JobStateStatus(builtins.str, enum.Enum):
 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'.

ABORTED = <JobStateStatus.ABORTED: 'Aborted'>
COMPLETED = <JobStateStatus.COMPLETED: 'Completed'>
FAILED = <JobStateStatus.FAILED: 'Failed'>
NEW = <JobStateStatus.NEW: 'New'>
STARTED = <JobStateStatus.STARTED: 'Started'>
class ListDatasetsResponse200:
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]):

ListDatasetsResponse200( 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.

datasets: list[Dataset]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
62    @property
63    def additional_keys(self) -> list[str]:
64        return list(self.additional_properties.keys())
class ListSegmentInstrumentsSegment(builtins.str, enum.Enum):
 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'.

FUTURES = <ListSegmentInstrumentsSegment.FUTURES: 'futures'>
class ListStrategiesResponse200:
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]):

ListStrategiesResponse200( 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.

strategies: list[StrategySummary]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
62    @property
63    def additional_keys(self) -> list[str]:
64        return list(self.additional_properties.keys())
class LiveCommandResult:
13@_attrs_define
14class LiveCommandResult:
15    """
16    Attributes:
17        run_id (str):
18        command_id (str): This command's own id, generated fresh for this call. A retried request is a second, distinct
19            command — this endpoint takes no idempotency key.
20        effective_at_ms (int): Epoch milliseconds — the market position every execution applies this command at.
21    """
22
23    run_id: str
24    command_id: str
25    effective_at_ms: int
26    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
27
28    def to_dict(self) -> dict[str, Any]:
29        run_id = self.run_id
30
31        command_id = self.command_id
32
33        effective_at_ms = self.effective_at_ms
34
35        field_dict: dict[str, Any] = {}
36        field_dict.update(self.additional_properties)
37        field_dict.update(
38            {
39                "runId": run_id,
40                "commandId": command_id,
41                "effectiveAtMs": effective_at_ms,
42            }
43        )
44
45        return field_dict
46
47    @classmethod
48    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
49        d = dict(src_dict)
50        run_id = d.pop("runId")
51
52        command_id = d.pop("commandId")
53
54        effective_at_ms = d.pop("effectiveAtMs")
55
56        live_command_result = cls(
57            run_id=run_id,
58            command_id=command_id,
59            effective_at_ms=effective_at_ms,
60        )
61
62        live_command_result.additional_properties = d
63        return live_command_result
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: run_id (str): command_id (str): This command's own id, generated fresh for this call. A retried request is a second, distinct command — this endpoint takes no idempotency key. effective_at_ms (int): Epoch milliseconds — the market position every execution applies this command at.

LiveCommandResult(run_id: str, command_id: str, effective_at_ms: int)
26def __init__(self, run_id, command_id, effective_at_ms):
27    self.run_id = run_id
28    self.command_id = command_id
29    self.effective_at_ms = effective_at_ms
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveCommandResult.

run_id: str
command_id: str
effective_at_ms: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
28    def to_dict(self) -> dict[str, Any]:
29        run_id = self.run_id
30
31        command_id = self.command_id
32
33        effective_at_ms = self.effective_at_ms
34
35        field_dict: dict[str, Any] = {}
36        field_dict.update(self.additional_properties)
37        field_dict.update(
38            {
39                "runId": run_id,
40                "commandId": command_id,
41                "effectiveAtMs": effective_at_ms,
42            }
43        )
44
45        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
47    @classmethod
48    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
49        d = dict(src_dict)
50        run_id = d.pop("runId")
51
52        command_id = d.pop("commandId")
53
54        effective_at_ms = d.pop("effectiveAtMs")
55
56        live_command_result = cls(
57            run_id=run_id,
58            command_id=command_id,
59            effective_at_ms=effective_at_ms,
60        )
61
62        live_command_result.additional_properties = d
63        return live_command_result
additional_keys: list[str]
65    @property
66    def additional_keys(self) -> list[str]:
67        return list(self.additional_properties.keys())
class LiveConnectionToken:
13@_attrs_define
14class LiveConnectionToken:
15    """
16    Attributes:
17        token (str): Pass as the `token` field of the WebSocket `connect` command — see the "Live execution" guide.
18        expires_at_ms (int):
19    """
20
21    token: str
22    expires_at_ms: int
23    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
24
25    def to_dict(self) -> dict[str, Any]:
26        token = self.token
27
28        expires_at_ms = self.expires_at_ms
29
30        field_dict: dict[str, Any] = {}
31        field_dict.update(self.additional_properties)
32        field_dict.update(
33            {
34                "token": token,
35                "expiresAtMs": expires_at_ms,
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        token = d.pop("token")
45
46        expires_at_ms = d.pop("expiresAtMs")
47
48        live_connection_token = cls(
49            token=token,
50            expires_at_ms=expires_at_ms,
51        )
52
53        live_connection_token.additional_properties = d
54        return live_connection_token
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: token (str): Pass as the token field of the WebSocket connect command — see the "Live execution" guide. expires_at_ms (int):

LiveConnectionToken(token: str, expires_at_ms: int)
25def __init__(self, token, expires_at_ms):
26    self.token = token
27    self.expires_at_ms = expires_at_ms
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveConnectionToken.

token: str
expires_at_ms: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
25    def to_dict(self) -> dict[str, Any]:
26        token = self.token
27
28        expires_at_ms = self.expires_at_ms
29
30        field_dict: dict[str, Any] = {}
31        field_dict.update(self.additional_properties)
32        field_dict.update(
33            {
34                "token": token,
35                "expiresAtMs": expires_at_ms,
36            }
37        )
38
39        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
41    @classmethod
42    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
43        d = dict(src_dict)
44        token = d.pop("token")
45
46        expires_at_ms = d.pop("expiresAtMs")
47
48        live_connection_token = cls(
49            token=token,
50            expires_at_ms=expires_at_ms,
51        )
52
53        live_connection_token.additional_properties = d
54        return live_connection_token
additional_keys: list[str]
56    @property
57    def additional_keys(self) -> list[str]:
58        return list(self.additional_properties.keys())
class LiveListResponse:
20@_attrs_define
21class LiveListResponse:
22    """
23    Attributes:
24        runs (list[LiveRunSummary]):
25        field_links (PublicLiveListLinks | Unset): Present only when another page exists.
26    """
27
28    runs: list[LiveRunSummary]
29    field_links: PublicLiveListLinks | Unset = UNSET
30    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
31
32    def to_dict(self) -> dict[str, Any]:
33        runs = []
34        for runs_item_data in self.runs:
35            runs_item = runs_item_data.to_dict()
36            runs.append(runs_item)
37
38        field_links: dict[str, Any] | Unset = UNSET
39        if not isinstance(self.field_links, Unset):
40            field_links = self.field_links.to_dict()
41
42        field_dict: dict[str, Any] = {}
43        field_dict.update(self.additional_properties)
44        field_dict.update(
45            {
46                "runs": runs,
47            }
48        )
49        if field_links is not UNSET:
50            field_dict["_links"] = field_links
51
52        return field_dict
53
54    @classmethod
55    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
56        from ..models.live_run_summary import LiveRunSummary
57        from ..models.public_live_list_links import PublicLiveListLinks
58
59        d = dict(src_dict)
60        runs = []
61        _runs = d.pop("runs")
62        for runs_item_data in _runs:
63            runs_item = LiveRunSummary.from_dict(runs_item_data)
64
65            runs.append(runs_item)
66
67        _field_links = d.pop("_links", UNSET)
68        field_links: PublicLiveListLinks | Unset
69        if isinstance(_field_links, Unset):
70            field_links = UNSET
71        else:
72            field_links = PublicLiveListLinks.from_dict(_field_links)
73
74        live_list_response = cls(
75            runs=runs,
76            field_links=field_links,
77        )
78
79        live_list_response.additional_properties = d
80        return live_list_response
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: runs (list[LiveRunSummary]): field_links (PublicLiveListLinks | Unset): Present only when another page exists.

LiveListResponse( runs: list[LiveRunSummary], field_links: PublicLiveListLinks | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
25def __init__(self, runs, field_links=attr_dict['field_links'].default):
26    self.runs = runs
27    self.field_links = field_links
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveListResponse.

runs: list[LiveRunSummary]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
32    def to_dict(self) -> dict[str, Any]:
33        runs = []
34        for runs_item_data in self.runs:
35            runs_item = runs_item_data.to_dict()
36            runs.append(runs_item)
37
38        field_links: dict[str, Any] | Unset = UNSET
39        if not isinstance(self.field_links, Unset):
40            field_links = self.field_links.to_dict()
41
42        field_dict: dict[str, Any] = {}
43        field_dict.update(self.additional_properties)
44        field_dict.update(
45            {
46                "runs": runs,
47            }
48        )
49        if field_links is not UNSET:
50            field_dict["_links"] = field_links
51
52        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
54    @classmethod
55    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
56        from ..models.live_run_summary import LiveRunSummary
57        from ..models.public_live_list_links import PublicLiveListLinks
58
59        d = dict(src_dict)
60        runs = []
61        _runs = d.pop("runs")
62        for runs_item_data in _runs:
63            runs_item = LiveRunSummary.from_dict(runs_item_data)
64
65            runs.append(runs_item)
66
67        _field_links = d.pop("_links", UNSET)
68        field_links: PublicLiveListLinks | Unset
69        if isinstance(_field_links, Unset):
70            field_links = UNSET
71        else:
72            field_links = PublicLiveListLinks.from_dict(_field_links)
73
74        live_list_response = cls(
75            runs=runs,
76            field_links=field_links,
77        )
78
79        live_list_response.additional_properties = d
80        return live_list_response
additional_keys: list[str]
82    @property
83    def additional_keys(self) -> list[str]:
84        return list(self.additional_properties.keys())
class LivePaper:
19@_attrs_define
20class LivePaper:
21    """
22    Attributes:
23        run_id (str):
24        stage (LivePaperStage):
25        accounts (list[LivePaperAccount]):
26    """
27
28    run_id: str
29    stage: LivePaperStage
30    accounts: list[LivePaperAccount]
31    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
32
33    def to_dict(self) -> dict[str, Any]:
34        run_id = self.run_id
35
36        stage = self.stage.value
37
38        accounts = []
39        for accounts_item_data in self.accounts:
40            accounts_item = accounts_item_data.to_dict()
41            accounts.append(accounts_item)
42
43        field_dict: dict[str, Any] = {}
44        field_dict.update(self.additional_properties)
45        field_dict.update(
46            {
47                "runId": run_id,
48                "stage": stage,
49                "accounts": accounts,
50            }
51        )
52
53        return field_dict
54
55    @classmethod
56    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
57        from ..models.live_paper_account import LivePaperAccount
58
59        d = dict(src_dict)
60        run_id = d.pop("runId")
61
62        stage = LivePaperStage(d.pop("stage"))
63
64        accounts = []
65        _accounts = d.pop("accounts")
66        for accounts_item_data in _accounts:
67            accounts_item = LivePaperAccount.from_dict(accounts_item_data)
68
69            accounts.append(accounts_item)
70
71        live_paper = cls(
72            run_id=run_id,
73            stage=stage,
74            accounts=accounts,
75        )
76
77        live_paper.additional_properties = d
78        return live_paper
79
80    @property
81    def additional_keys(self) -> list[str]:
82        return list(self.additional_properties.keys())
83
84    def __getitem__(self, key: str) -> Any:
85        return self.additional_properties[key]
86
87    def __setitem__(self, key: str, value: Any) -> None:
88        self.additional_properties[key] = value
89
90    def __delitem__(self, key: str) -> None:
91        del self.additional_properties[key]
92
93    def __contains__(self, key: str) -> bool:
94        return key in self.additional_properties

Attributes: run_id (str): stage (LivePaperStage): accounts (list[LivePaperAccount]):

LivePaper( run_id: str, stage: LivePaperStage, accounts: list[LivePaperAccount])
26def __init__(self, run_id, stage, accounts):
27    self.run_id = run_id
28    self.stage = stage
29    self.accounts = accounts
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LivePaper.

run_id: str
accounts: list[LivePaperAccount]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
33    def to_dict(self) -> dict[str, Any]:
34        run_id = self.run_id
35
36        stage = self.stage.value
37
38        accounts = []
39        for accounts_item_data in self.accounts:
40            accounts_item = accounts_item_data.to_dict()
41            accounts.append(accounts_item)
42
43        field_dict: dict[str, Any] = {}
44        field_dict.update(self.additional_properties)
45        field_dict.update(
46            {
47                "runId": run_id,
48                "stage": stage,
49                "accounts": accounts,
50            }
51        )
52
53        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
55    @classmethod
56    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
57        from ..models.live_paper_account import LivePaperAccount
58
59        d = dict(src_dict)
60        run_id = d.pop("runId")
61
62        stage = LivePaperStage(d.pop("stage"))
63
64        accounts = []
65        _accounts = d.pop("accounts")
66        for accounts_item_data in _accounts:
67            accounts_item = LivePaperAccount.from_dict(accounts_item_data)
68
69            accounts.append(accounts_item)
70
71        live_paper = cls(
72            run_id=run_id,
73            stage=stage,
74            accounts=accounts,
75        )
76
77        live_paper.additional_properties = d
78        return live_paper
additional_keys: list[str]
80    @property
81    def additional_keys(self) -> list[str]:
82        return list(self.additional_properties.keys())
class LivePaperAccount:
 21@_attrs_define
 22class LivePaperAccount:
 23    """One simulated account — one per quote currency the run trades.
 24
 25    Attributes:
 26        currency (str): The account's quote currency; every amount below is in it.
 27        initial_funding (float):
 28        equity (float): Latest recorded equity — see `equityKind`.
 29        realised_pnl (float): Sum of the PnL of the closed trades.
 30        trades (int): Closed trades.
 31        gaps (int): Times open positions were lost because the run was restarted with them open.
 32        open_positions (list[LivePaperPosition]):
 33        equity_at_ms (int | Unset): Market time of that value. Absent while the account holds its starting capital.
 34        equity_kind (LivePaperAccountEquityKind | Unset): `equity` at a closed trade, `mark` at a periodic mark-to-
 35            market (includes open positions at market price).
 36        kpi (LivePaperKpi | Unset): The same KPIs a backtest reports, over the trades closed so far. Absent until the
 37            first closed trade is recorded.
 38    """
 39
 40    currency: str
 41    initial_funding: float
 42    equity: float
 43    realised_pnl: float
 44    trades: int
 45    gaps: int
 46    open_positions: list[LivePaperPosition]
 47    equity_at_ms: int | Unset = UNSET
 48    equity_kind: LivePaperAccountEquityKind | Unset = UNSET
 49    kpi: LivePaperKpi | Unset = UNSET
 50    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 51
 52    def to_dict(self) -> dict[str, Any]:
 53        currency = self.currency
 54
 55        initial_funding = self.initial_funding
 56
 57        equity = self.equity
 58
 59        realised_pnl = self.realised_pnl
 60
 61        trades = self.trades
 62
 63        gaps = self.gaps
 64
 65        open_positions = []
 66        for open_positions_item_data in self.open_positions:
 67            open_positions_item = open_positions_item_data.to_dict()
 68            open_positions.append(open_positions_item)
 69
 70        equity_at_ms = self.equity_at_ms
 71
 72        equity_kind: str | Unset = UNSET
 73        if not isinstance(self.equity_kind, Unset):
 74            equity_kind = self.equity_kind.value
 75
 76        kpi: dict[str, Any] | Unset = UNSET
 77        if not isinstance(self.kpi, Unset):
 78            kpi = self.kpi.to_dict()
 79
 80        field_dict: dict[str, Any] = {}
 81        field_dict.update(self.additional_properties)
 82        field_dict.update(
 83            {
 84                "currency": currency,
 85                "initialFunding": initial_funding,
 86                "equity": equity,
 87                "realisedPnl": realised_pnl,
 88                "trades": trades,
 89                "gaps": gaps,
 90                "openPositions": open_positions,
 91            }
 92        )
 93        if equity_at_ms is not UNSET:
 94            field_dict["equityAtMs"] = equity_at_ms
 95        if equity_kind is not UNSET:
 96            field_dict["equityKind"] = equity_kind
 97        if kpi is not UNSET:
 98            field_dict["kpi"] = kpi
 99
100        return field_dict
101
102    @classmethod
103    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
104        from ..models.live_paper_kpi import LivePaperKpi
105        from ..models.live_paper_position import LivePaperPosition
106
107        d = dict(src_dict)
108        currency = d.pop("currency")
109
110        initial_funding = d.pop("initialFunding")
111
112        equity = d.pop("equity")
113
114        realised_pnl = d.pop("realisedPnl")
115
116        trades = d.pop("trades")
117
118        gaps = d.pop("gaps")
119
120        open_positions = []
121        _open_positions = d.pop("openPositions")
122        for open_positions_item_data in _open_positions:
123            open_positions_item = LivePaperPosition.from_dict(open_positions_item_data)
124
125            open_positions.append(open_positions_item)
126
127        equity_at_ms = d.pop("equityAtMs", UNSET)
128
129        _equity_kind = d.pop("equityKind", UNSET)
130        equity_kind: LivePaperAccountEquityKind | Unset
131        if isinstance(_equity_kind, Unset):
132            equity_kind = UNSET
133        else:
134            equity_kind = LivePaperAccountEquityKind(_equity_kind)
135
136        _kpi = d.pop("kpi", UNSET)
137        kpi: LivePaperKpi | Unset
138        if isinstance(_kpi, Unset):
139            kpi = UNSET
140        else:
141            kpi = LivePaperKpi.from_dict(_kpi)
142
143        live_paper_account = cls(
144            currency=currency,
145            initial_funding=initial_funding,
146            equity=equity,
147            realised_pnl=realised_pnl,
148            trades=trades,
149            gaps=gaps,
150            open_positions=open_positions,
151            equity_at_ms=equity_at_ms,
152            equity_kind=equity_kind,
153            kpi=kpi,
154        )
155
156        live_paper_account.additional_properties = d
157        return live_paper_account
158
159    @property
160    def additional_keys(self) -> list[str]:
161        return list(self.additional_properties.keys())
162
163    def __getitem__(self, key: str) -> Any:
164        return self.additional_properties[key]
165
166    def __setitem__(self, key: str, value: Any) -> None:
167        self.additional_properties[key] = value
168
169    def __delitem__(self, key: str) -> None:
170        del self.additional_properties[key]
171
172    def __contains__(self, key: str) -> bool:
173        return key in self.additional_properties

One simulated account — one per quote currency the run trades.

Attributes: currency (str): The account's quote currency; every amount below is in it. initial_funding (float): equity (float): Latest recorded equity — see equityKind. realised_pnl (float): Sum of the PnL of the closed trades. trades (int): Closed trades. gaps (int): Times open positions were lost because the run was restarted with them open. open_positions (list[LivePaperPosition]): equity_at_ms (int | Unset): Market time of that value. Absent while the account holds its starting capital. equity_kind (LivePaperAccountEquityKind | Unset): equity at a closed trade, mark at a periodic mark-to- market (includes open positions at market price). kpi (LivePaperKpi | Unset): The same KPIs a backtest reports, over the trades closed so far. Absent until the first closed trade is recorded.

LivePaperAccount( currency: str, initial_funding: float, equity: float, realised_pnl: float, trades: int, gaps: int, open_positions: list[LivePaperPosition], equity_at_ms: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, equity_kind: LivePaperAccountEquityKind | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, kpi: LivePaperKpi | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
33def __init__(self, currency, initial_funding, equity, realised_pnl, trades, gaps, open_positions, equity_at_ms=attr_dict['equity_at_ms'].default, equity_kind=attr_dict['equity_kind'].default, kpi=attr_dict['kpi'].default):
34    self.currency = currency
35    self.initial_funding = initial_funding
36    self.equity = equity
37    self.realised_pnl = realised_pnl
38    self.trades = trades
39    self.gaps = gaps
40    self.open_positions = open_positions
41    self.equity_at_ms = equity_at_ms
42    self.equity_kind = equity_kind
43    self.kpi = kpi
44    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LivePaperAccount.

currency: str
initial_funding: float
equity: float
realised_pnl: float
trades: int
gaps: int
open_positions: list[LivePaperPosition]
equity_at_ms: int | qtsurfer.api.client._generated.types.Unset
equity_kind: LivePaperAccountEquityKind | qtsurfer.api.client._generated.types.Unset
kpi: LivePaperKpi | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 52    def to_dict(self) -> dict[str, Any]:
 53        currency = self.currency
 54
 55        initial_funding = self.initial_funding
 56
 57        equity = self.equity
 58
 59        realised_pnl = self.realised_pnl
 60
 61        trades = self.trades
 62
 63        gaps = self.gaps
 64
 65        open_positions = []
 66        for open_positions_item_data in self.open_positions:
 67            open_positions_item = open_positions_item_data.to_dict()
 68            open_positions.append(open_positions_item)
 69
 70        equity_at_ms = self.equity_at_ms
 71
 72        equity_kind: str | Unset = UNSET
 73        if not isinstance(self.equity_kind, Unset):
 74            equity_kind = self.equity_kind.value
 75
 76        kpi: dict[str, Any] | Unset = UNSET
 77        if not isinstance(self.kpi, Unset):
 78            kpi = self.kpi.to_dict()
 79
 80        field_dict: dict[str, Any] = {}
 81        field_dict.update(self.additional_properties)
 82        field_dict.update(
 83            {
 84                "currency": currency,
 85                "initialFunding": initial_funding,
 86                "equity": equity,
 87                "realisedPnl": realised_pnl,
 88                "trades": trades,
 89                "gaps": gaps,
 90                "openPositions": open_positions,
 91            }
 92        )
 93        if equity_at_ms is not UNSET:
 94            field_dict["equityAtMs"] = equity_at_ms
 95        if equity_kind is not UNSET:
 96            field_dict["equityKind"] = equity_kind
 97        if kpi is not UNSET:
 98            field_dict["kpi"] = kpi
 99
100        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
102    @classmethod
103    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
104        from ..models.live_paper_kpi import LivePaperKpi
105        from ..models.live_paper_position import LivePaperPosition
106
107        d = dict(src_dict)
108        currency = d.pop("currency")
109
110        initial_funding = d.pop("initialFunding")
111
112        equity = d.pop("equity")
113
114        realised_pnl = d.pop("realisedPnl")
115
116        trades = d.pop("trades")
117
118        gaps = d.pop("gaps")
119
120        open_positions = []
121        _open_positions = d.pop("openPositions")
122        for open_positions_item_data in _open_positions:
123            open_positions_item = LivePaperPosition.from_dict(open_positions_item_data)
124
125            open_positions.append(open_positions_item)
126
127        equity_at_ms = d.pop("equityAtMs", UNSET)
128
129        _equity_kind = d.pop("equityKind", UNSET)
130        equity_kind: LivePaperAccountEquityKind | Unset
131        if isinstance(_equity_kind, Unset):
132            equity_kind = UNSET
133        else:
134            equity_kind = LivePaperAccountEquityKind(_equity_kind)
135
136        _kpi = d.pop("kpi", UNSET)
137        kpi: LivePaperKpi | Unset
138        if isinstance(_kpi, Unset):
139            kpi = UNSET
140        else:
141            kpi = LivePaperKpi.from_dict(_kpi)
142
143        live_paper_account = cls(
144            currency=currency,
145            initial_funding=initial_funding,
146            equity=equity,
147            realised_pnl=realised_pnl,
148            trades=trades,
149            gaps=gaps,
150            open_positions=open_positions,
151            equity_at_ms=equity_at_ms,
152            equity_kind=equity_kind,
153            kpi=kpi,
154        )
155
156        live_paper_account.additional_properties = d
157        return live_paper_account
additional_keys: list[str]
159    @property
160    def additional_keys(self) -> list[str]:
161        return list(self.additional_properties.keys())
class LivePaperAccountEquityKind(builtins.str, enum.Enum):
 5class LivePaperAccountEquityKind(str, Enum):
 6    EQUITY = "equity"
 7    MARK = "mark"
 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'.

EQUITY = <LivePaperAccountEquityKind.EQUITY: 'equity'>
class LivePaperConfig:
 16@_attrs_define
 17class LivePaperConfig:
 18    """Paper trading for this run: the same economics as a backtest's `baseConfig` (same fields,
 19    defaults and limits), plus `output`. An empty object takes every default. Each quote
 20    currency the run trades gets its own simulated account, opened with `initialFunding` in
 21    that currency; accounts are never added together. As returned on a run, the block is
 22    normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
 23    in.
 24
 25        Attributes:
 26            initial_funding (float | Unset): Starting capital of each account, in that account's own quote currency.
 27                Default: 100.0.
 28            fee_rate (float | Unset): Fee rate for both sides (0.001 = 0.1%). Accepted on start; returned resolved into the
 29                two fields below. Default: 0.001.
 30            buy_fee_rate (float | Unset): Buy-side fee rate; overrides `feeRate`.
 31            sell_fee_rate (float | Unset): Sell-side fee rate; overrides `feeRate`.
 32            fee_leg (LivePaperConfigFeeLeg | Unset): Which asset fees are charged in. Case-insensitive on start. Default:
 33                LivePaperConfigFeeLeg.RECEIVED.
 34            percent_amount_to_lock (float | Unset): Share of the account's free balance each entry locks, in percent.
 35                Omitted, the strategy's own setting applies, and without one 10%.
 36            output (LivePaperConfigOutput | Unset): `separate` keeps paper output out of the run's signals (read it with
 37                `GET /live/{runId}/paper`); `mix` also interleaves it into the run's signals as `type: paper`, right after the
 38                signal that caused it. Default: LivePaperConfigOutput.SEPARATE.
 39    """
 40
 41    initial_funding: float | Unset = 100.0
 42    fee_rate: float | Unset = 0.001
 43    buy_fee_rate: float | Unset = UNSET
 44    sell_fee_rate: float | Unset = UNSET
 45    fee_leg: LivePaperConfigFeeLeg | Unset = LivePaperConfigFeeLeg.RECEIVED
 46    percent_amount_to_lock: float | Unset = UNSET
 47    output: LivePaperConfigOutput | Unset = LivePaperConfigOutput.SEPARATE
 48
 49    def to_dict(self) -> dict[str, Any]:
 50        initial_funding = self.initial_funding
 51
 52        fee_rate = self.fee_rate
 53
 54        buy_fee_rate = self.buy_fee_rate
 55
 56        sell_fee_rate = self.sell_fee_rate
 57
 58        fee_leg: str | Unset = UNSET
 59        if not isinstance(self.fee_leg, Unset):
 60            fee_leg = self.fee_leg.value
 61
 62        percent_amount_to_lock = self.percent_amount_to_lock
 63
 64        output: str | Unset = UNSET
 65        if not isinstance(self.output, Unset):
 66            output = self.output.value
 67
 68        field_dict: dict[str, Any] = {}
 69
 70        field_dict.update({})
 71        if initial_funding is not UNSET:
 72            field_dict["initialFunding"] = initial_funding
 73        if fee_rate is not UNSET:
 74            field_dict["feeRate"] = fee_rate
 75        if buy_fee_rate is not UNSET:
 76            field_dict["buyFeeRate"] = buy_fee_rate
 77        if sell_fee_rate is not UNSET:
 78            field_dict["sellFeeRate"] = sell_fee_rate
 79        if fee_leg is not UNSET:
 80            field_dict["feeLeg"] = fee_leg
 81        if percent_amount_to_lock is not UNSET:
 82            field_dict["percentAmountToLock"] = percent_amount_to_lock
 83        if output is not UNSET:
 84            field_dict["output"] = output
 85
 86        return field_dict
 87
 88    @classmethod
 89    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 90        d = dict(src_dict)
 91        initial_funding = d.pop("initialFunding", UNSET)
 92
 93        fee_rate = d.pop("feeRate", UNSET)
 94
 95        buy_fee_rate = d.pop("buyFeeRate", UNSET)
 96
 97        sell_fee_rate = d.pop("sellFeeRate", UNSET)
 98
 99        _fee_leg = d.pop("feeLeg", UNSET)
100        fee_leg: LivePaperConfigFeeLeg | Unset
101        if isinstance(_fee_leg, Unset):
102            fee_leg = UNSET
103        else:
104            fee_leg = LivePaperConfigFeeLeg(_fee_leg)
105
106        percent_amount_to_lock = d.pop("percentAmountToLock", UNSET)
107
108        _output = d.pop("output", UNSET)
109        output: LivePaperConfigOutput | Unset
110        if isinstance(_output, Unset):
111            output = UNSET
112        else:
113            output = LivePaperConfigOutput(_output)
114
115        live_paper_config = cls(
116            initial_funding=initial_funding,
117            fee_rate=fee_rate,
118            buy_fee_rate=buy_fee_rate,
119            sell_fee_rate=sell_fee_rate,
120            fee_leg=fee_leg,
121            percent_amount_to_lock=percent_amount_to_lock,
122            output=output,
123        )
124
125        return live_paper_config

Paper trading for this run: the same economics as a backtest's baseConfig (same fields, defaults and limits), plus output. An empty object takes every default. Each quote currency the run trades gets its own simulated account, opened with initialFunding in that currency; accounts are never added together. As returned on a run, the block is normalised: feeRate is resolved into buyFeeRate/sellFeeRate and defaults are filled in.

Attributes:
    initial_funding (float | Unset): Starting capital of each account, in that account's own quote currency.
        Default: 100.0.
    fee_rate (float | Unset): Fee rate for both sides (0.001 = 0.1%). Accepted on start; returned resolved into the
        two fields below. Default: 0.001.
    buy_fee_rate (float | Unset): Buy-side fee rate; overrides `feeRate`.
    sell_fee_rate (float | Unset): Sell-side fee rate; overrides `feeRate`.
    fee_leg (LivePaperConfigFeeLeg | Unset): Which asset fees are charged in. Case-insensitive on start. Default:
        LivePaperConfigFeeLeg.RECEIVED.
    percent_amount_to_lock (float | Unset): Share of the account's free balance each entry locks, in percent.
        Omitted, the strategy's own setting applies, and without one 10%.
    output (LivePaperConfigOutput | Unset): `separate` keeps paper output out of the run's signals (read it with
        `GET /live/{runId}/paper`); `mix` also interleaves it into the run's signals as `type: paper`, right after the
        signal that caused it. Default: LivePaperConfigOutput.SEPARATE.
LivePaperConfig( initial_funding: float | qtsurfer.api.client._generated.types.Unset = 100.0, fee_rate: float | qtsurfer.api.client._generated.types.Unset = 0.001, buy_fee_rate: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, sell_fee_rate: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, fee_leg: LivePaperConfigFeeLeg | qtsurfer.api.client._generated.types.Unset = <LivePaperConfigFeeLeg.RECEIVED: 'RECEIVED'>, percent_amount_to_lock: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, output: LivePaperConfigOutput | qtsurfer.api.client._generated.types.Unset = <LivePaperConfigOutput.SEPARATE: 'separate'>)
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, output=attr_dict['output'].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.output = output

Method generated by attrs for class LivePaperConfig.

initial_funding: float | qtsurfer.api.client._generated.types.Unset
fee_rate: float | qtsurfer.api.client._generated.types.Unset
buy_fee_rate: float | qtsurfer.api.client._generated.types.Unset
sell_fee_rate: float | qtsurfer.api.client._generated.types.Unset
fee_leg: LivePaperConfigFeeLeg | qtsurfer.api.client._generated.types.Unset
percent_amount_to_lock: float | qtsurfer.api.client._generated.types.Unset
output: LivePaperConfigOutput | qtsurfer.api.client._generated.types.Unset
def to_dict(self) -> dict[str, typing.Any]:
49    def to_dict(self) -> dict[str, Any]:
50        initial_funding = self.initial_funding
51
52        fee_rate = self.fee_rate
53
54        buy_fee_rate = self.buy_fee_rate
55
56        sell_fee_rate = self.sell_fee_rate
57
58        fee_leg: str | Unset = UNSET
59        if not isinstance(self.fee_leg, Unset):
60            fee_leg = self.fee_leg.value
61
62        percent_amount_to_lock = self.percent_amount_to_lock
63
64        output: str | Unset = UNSET
65        if not isinstance(self.output, Unset):
66            output = self.output.value
67
68        field_dict: dict[str, Any] = {}
69
70        field_dict.update({})
71        if initial_funding is not UNSET:
72            field_dict["initialFunding"] = initial_funding
73        if fee_rate is not UNSET:
74            field_dict["feeRate"] = fee_rate
75        if buy_fee_rate is not UNSET:
76            field_dict["buyFeeRate"] = buy_fee_rate
77        if sell_fee_rate is not UNSET:
78            field_dict["sellFeeRate"] = sell_fee_rate
79        if fee_leg is not UNSET:
80            field_dict["feeLeg"] = fee_leg
81        if percent_amount_to_lock is not UNSET:
82            field_dict["percentAmountToLock"] = percent_amount_to_lock
83        if output is not UNSET:
84            field_dict["output"] = output
85
86        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 88    @classmethod
 89    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 90        d = dict(src_dict)
 91        initial_funding = d.pop("initialFunding", UNSET)
 92
 93        fee_rate = d.pop("feeRate", UNSET)
 94
 95        buy_fee_rate = d.pop("buyFeeRate", UNSET)
 96
 97        sell_fee_rate = d.pop("sellFeeRate", UNSET)
 98
 99        _fee_leg = d.pop("feeLeg", UNSET)
100        fee_leg: LivePaperConfigFeeLeg | Unset
101        if isinstance(_fee_leg, Unset):
102            fee_leg = UNSET
103        else:
104            fee_leg = LivePaperConfigFeeLeg(_fee_leg)
105
106        percent_amount_to_lock = d.pop("percentAmountToLock", UNSET)
107
108        _output = d.pop("output", UNSET)
109        output: LivePaperConfigOutput | Unset
110        if isinstance(_output, Unset):
111            output = UNSET
112        else:
113            output = LivePaperConfigOutput(_output)
114
115        live_paper_config = cls(
116            initial_funding=initial_funding,
117            fee_rate=fee_rate,
118            buy_fee_rate=buy_fee_rate,
119            sell_fee_rate=sell_fee_rate,
120            fee_leg=fee_leg,
121            percent_amount_to_lock=percent_amount_to_lock,
122            output=output,
123        )
124
125        return live_paper_config
class LivePaperConfigFeeLeg(builtins.str, enum.Enum):
 5class LivePaperConfigFeeLeg(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'.

BASE = <LivePaperConfigFeeLeg.BASE: 'BASE'>
QUOTE = <LivePaperConfigFeeLeg.QUOTE: 'QUOTE'>
RECEIVED = <LivePaperConfigFeeLeg.RECEIVED: 'RECEIVED'>
class LivePaperConfigOutput(builtins.str, enum.Enum):
 5class LivePaperConfigOutput(str, Enum):
 6    MIX = "mix"
 7    SEPARATE = "separate"
 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'.

MIX = <LivePaperConfigOutput.MIX: 'mix'>
SEPARATE = <LivePaperConfigOutput.SEPARATE: 'separate'>
class LivePaperEquityPage:
20@_attrs_define
21class LivePaperEquityPage:
22    """
23    Attributes:
24        points (list[LivePaperEquityPoint]):
25        field_links (LivePaperEquityPageLinks | Unset):
26    """
27
28    points: list[LivePaperEquityPoint]
29    field_links: LivePaperEquityPageLinks | Unset = UNSET
30    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
31
32    def to_dict(self) -> dict[str, Any]:
33        points = []
34        for points_item_data in self.points:
35            points_item = points_item_data.to_dict()
36            points.append(points_item)
37
38        field_links: dict[str, Any] | Unset = UNSET
39        if not isinstance(self.field_links, Unset):
40            field_links = self.field_links.to_dict()
41
42        field_dict: dict[str, Any] = {}
43        field_dict.update(self.additional_properties)
44        field_dict.update(
45            {
46                "points": points,
47            }
48        )
49        if field_links is not UNSET:
50            field_dict["_links"] = field_links
51
52        return field_dict
53
54    @classmethod
55    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
56        from ..models.live_paper_equity_page_links import LivePaperEquityPageLinks
57        from ..models.live_paper_equity_point import LivePaperEquityPoint
58
59        d = dict(src_dict)
60        points = []
61        _points = d.pop("points")
62        for points_item_data in _points:
63            points_item = LivePaperEquityPoint.from_dict(points_item_data)
64
65            points.append(points_item)
66
67        _field_links = d.pop("_links", UNSET)
68        field_links: LivePaperEquityPageLinks | Unset
69        if isinstance(_field_links, Unset):
70            field_links = UNSET
71        else:
72            field_links = LivePaperEquityPageLinks.from_dict(_field_links)
73
74        live_paper_equity_page = cls(
75            points=points,
76            field_links=field_links,
77        )
78
79        live_paper_equity_page.additional_properties = d
80        return live_paper_equity_page
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: points (list[LivePaperEquityPoint]): field_links (LivePaperEquityPageLinks | Unset):

LivePaperEquityPage( points: list[LivePaperEquityPoint], field_links: LivePaperEquityPageLinks | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
25def __init__(self, points, field_links=attr_dict['field_links'].default):
26    self.points = points
27    self.field_links = field_links
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LivePaperEquityPage.

points: list[LivePaperEquityPoint]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
32    def to_dict(self) -> dict[str, Any]:
33        points = []
34        for points_item_data in self.points:
35            points_item = points_item_data.to_dict()
36            points.append(points_item)
37
38        field_links: dict[str, Any] | Unset = UNSET
39        if not isinstance(self.field_links, Unset):
40            field_links = self.field_links.to_dict()
41
42        field_dict: dict[str, Any] = {}
43        field_dict.update(self.additional_properties)
44        field_dict.update(
45            {
46                "points": points,
47            }
48        )
49        if field_links is not UNSET:
50            field_dict["_links"] = field_links
51
52        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
54    @classmethod
55    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
56        from ..models.live_paper_equity_page_links import LivePaperEquityPageLinks
57        from ..models.live_paper_equity_point import LivePaperEquityPoint
58
59        d = dict(src_dict)
60        points = []
61        _points = d.pop("points")
62        for points_item_data in _points:
63            points_item = LivePaperEquityPoint.from_dict(points_item_data)
64
65            points.append(points_item)
66
67        _field_links = d.pop("_links", UNSET)
68        field_links: LivePaperEquityPageLinks | Unset
69        if isinstance(_field_links, Unset):
70            field_links = UNSET
71        else:
72            field_links = LivePaperEquityPageLinks.from_dict(_field_links)
73
74        live_paper_equity_page = cls(
75            points=points,
76            field_links=field_links,
77        )
78
79        live_paper_equity_page.additional_properties = d
80        return live_paper_equity_page
additional_keys: list[str]
82    @property
83    def additional_keys(self) -> list[str]:
84        return list(self.additional_properties.keys())
class LivePaperEquityPageLinksNext:
15@_attrs_define
16class LivePaperEquityPageLinksNext:
17    """
18    Attributes:
19        href (str | Unset):
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        live_paper_equity_page_links_next = cls(
42            href=href,
43        )
44
45        live_paper_equity_page_links_next.additional_properties = d
46        return live_paper_equity_page_links_next
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):

LivePaperEquityPageLinksNext( href: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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 LivePaperEquityPageLinksNext.

href: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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        live_paper_equity_page_links_next = cls(
42            href=href,
43        )
44
45        live_paper_equity_page_links_next.additional_properties = d
46        return live_paper_equity_page_links_next
additional_keys: list[str]
48    @property
49    def additional_keys(self) -> list[str]:
50        return list(self.additional_properties.keys())
class LivePaperEquityPoint:
16@_attrs_define
17class LivePaperEquityPoint:
18    """
19    Attributes:
20        currency (str):
21        kind (LivePaperEquityPointKind):
22        event_ts_ms (int): Market time of the point.
23        equity (float | Unset): Absent on a `gap`.
24    """
25
26    currency: str
27    kind: LivePaperEquityPointKind
28    event_ts_ms: int
29    equity: float | Unset = UNSET
30    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
31
32    def to_dict(self) -> dict[str, Any]:
33        currency = self.currency
34
35        kind = self.kind.value
36
37        event_ts_ms = self.event_ts_ms
38
39        equity = self.equity
40
41        field_dict: dict[str, Any] = {}
42        field_dict.update(self.additional_properties)
43        field_dict.update(
44            {
45                "currency": currency,
46                "kind": kind,
47                "eventTsMs": event_ts_ms,
48            }
49        )
50        if equity is not UNSET:
51            field_dict["equity"] = equity
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        currency = d.pop("currency")
59
60        kind = LivePaperEquityPointKind(d.pop("kind"))
61
62        event_ts_ms = d.pop("eventTsMs")
63
64        equity = d.pop("equity", UNSET)
65
66        live_paper_equity_point = cls(
67            currency=currency,
68            kind=kind,
69            event_ts_ms=event_ts_ms,
70            equity=equity,
71        )
72
73        live_paper_equity_point.additional_properties = d
74        return live_paper_equity_point
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

Attributes: currency (str): kind (LivePaperEquityPointKind): event_ts_ms (int): Market time of the point. equity (float | Unset): Absent on a gap.

LivePaperEquityPoint( currency: str, kind: LivePaperEquityPointKind, event_ts_ms: int, equity: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
27def __init__(self, currency, kind, event_ts_ms, equity=attr_dict['equity'].default):
28    self.currency = currency
29    self.kind = kind
30    self.event_ts_ms = event_ts_ms
31    self.equity = equity
32    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LivePaperEquityPoint.

currency: str
event_ts_ms: int
equity: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
32    def to_dict(self) -> dict[str, Any]:
33        currency = self.currency
34
35        kind = self.kind.value
36
37        event_ts_ms = self.event_ts_ms
38
39        equity = self.equity
40
41        field_dict: dict[str, Any] = {}
42        field_dict.update(self.additional_properties)
43        field_dict.update(
44            {
45                "currency": currency,
46                "kind": kind,
47                "eventTsMs": event_ts_ms,
48            }
49        )
50        if equity is not UNSET:
51            field_dict["equity"] = equity
52
53        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
55    @classmethod
56    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
57        d = dict(src_dict)
58        currency = d.pop("currency")
59
60        kind = LivePaperEquityPointKind(d.pop("kind"))
61
62        event_ts_ms = d.pop("eventTsMs")
63
64        equity = d.pop("equity", UNSET)
65
66        live_paper_equity_point = cls(
67            currency=currency,
68            kind=kind,
69            event_ts_ms=event_ts_ms,
70            equity=equity,
71        )
72
73        live_paper_equity_point.additional_properties = d
74        return live_paper_equity_point
additional_keys: list[str]
76    @property
77    def additional_keys(self) -> list[str]:
78        return list(self.additional_properties.keys())
class LivePaperEquityPointKind(builtins.str, enum.Enum):
 5class LivePaperEquityPointKind(str, Enum):
 6    EQUITY = "equity"
 7    GAP = "gap"
 8    MARK = "mark"
 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'.

EQUITY = <LivePaperEquityPointKind.EQUITY: 'equity'>
class LivePaperKpi:
 15@_attrs_define
 16class LivePaperKpi:
 17    """The same KPIs a backtest reports, over the trades closed so far. Absent until the first closed trade is recorded.
 18
 19    Attributes:
 20        total_trades (int | Unset):
 21        win_count (int | Unset):
 22        loss_count (int | Unset):
 23        win_rate (float | Unset): Ratio (0.5 = half the trades won).
 24        pnl_total (float | Unset):
 25        pnl_total_percent (float | Unset): Percent of `initialFunding` (0-100 scale).
 26        sharpe_ratio (float | None | Unset):
 27        sortino_ratio (float | None | Unset):
 28        cagr (float | None | Unset): Ratio (0.15 for 15%).
 29        max_drawdown (float | Unset):
 30        max_drawdown_percent (float | Unset): Percent (0-100 scale).
 31    """
 32
 33    total_trades: int | Unset = UNSET
 34    win_count: int | Unset = UNSET
 35    loss_count: int | Unset = UNSET
 36    win_rate: float | Unset = UNSET
 37    pnl_total: float | Unset = UNSET
 38    pnl_total_percent: float | Unset = UNSET
 39    sharpe_ratio: float | None | Unset = UNSET
 40    sortino_ratio: float | None | Unset = UNSET
 41    cagr: float | None | Unset = UNSET
 42    max_drawdown: float | Unset = UNSET
 43    max_drawdown_percent: float | Unset = UNSET
 44    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 45
 46    def to_dict(self) -> dict[str, Any]:
 47        total_trades = self.total_trades
 48
 49        win_count = self.win_count
 50
 51        loss_count = self.loss_count
 52
 53        win_rate = self.win_rate
 54
 55        pnl_total = self.pnl_total
 56
 57        pnl_total_percent = self.pnl_total_percent
 58
 59        sharpe_ratio: float | None | Unset
 60        if isinstance(self.sharpe_ratio, Unset):
 61            sharpe_ratio = UNSET
 62        else:
 63            sharpe_ratio = self.sharpe_ratio
 64
 65        sortino_ratio: float | None | Unset
 66        if isinstance(self.sortino_ratio, Unset):
 67            sortino_ratio = UNSET
 68        else:
 69            sortino_ratio = self.sortino_ratio
 70
 71        cagr: float | None | Unset
 72        if isinstance(self.cagr, Unset):
 73            cagr = UNSET
 74        else:
 75            cagr = self.cagr
 76
 77        max_drawdown = self.max_drawdown
 78
 79        max_drawdown_percent = self.max_drawdown_percent
 80
 81        field_dict: dict[str, Any] = {}
 82        field_dict.update(self.additional_properties)
 83        field_dict.update({})
 84        if total_trades is not UNSET:
 85            field_dict["totalTrades"] = total_trades
 86        if win_count is not UNSET:
 87            field_dict["winCount"] = win_count
 88        if loss_count is not UNSET:
 89            field_dict["lossCount"] = loss_count
 90        if win_rate is not UNSET:
 91            field_dict["winRate"] = win_rate
 92        if pnl_total is not UNSET:
 93            field_dict["pnlTotal"] = pnl_total
 94        if pnl_total_percent is not UNSET:
 95            field_dict["pnlTotalPercent"] = pnl_total_percent
 96        if sharpe_ratio is not UNSET:
 97            field_dict["sharpeRatio"] = sharpe_ratio
 98        if sortino_ratio is not UNSET:
 99            field_dict["sortinoRatio"] = sortino_ratio
100        if cagr is not UNSET:
101            field_dict["cagr"] = cagr
102        if max_drawdown is not UNSET:
103            field_dict["maxDrawdown"] = max_drawdown
104        if max_drawdown_percent is not UNSET:
105            field_dict["maxDrawdownPercent"] = max_drawdown_percent
106
107        return field_dict
108
109    @classmethod
110    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
111        d = dict(src_dict)
112        total_trades = d.pop("totalTrades", UNSET)
113
114        win_count = d.pop("winCount", UNSET)
115
116        loss_count = d.pop("lossCount", UNSET)
117
118        win_rate = d.pop("winRate", UNSET)
119
120        pnl_total = d.pop("pnlTotal", UNSET)
121
122        pnl_total_percent = d.pop("pnlTotalPercent", UNSET)
123
124        def _parse_sharpe_ratio(data: object) -> float | None | Unset:
125            if data is None:
126                return data
127            if isinstance(data, Unset):
128                return data
129            return cast(float | None | Unset, data)
130
131        sharpe_ratio = _parse_sharpe_ratio(d.pop("sharpeRatio", UNSET))
132
133        def _parse_sortino_ratio(data: object) -> float | None | Unset:
134            if data is None:
135                return data
136            if isinstance(data, Unset):
137                return data
138            return cast(float | None | Unset, data)
139
140        sortino_ratio = _parse_sortino_ratio(d.pop("sortinoRatio", UNSET))
141
142        def _parse_cagr(data: object) -> float | None | Unset:
143            if data is None:
144                return data
145            if isinstance(data, Unset):
146                return data
147            return cast(float | None | Unset, data)
148
149        cagr = _parse_cagr(d.pop("cagr", UNSET))
150
151        max_drawdown = d.pop("maxDrawdown", UNSET)
152
153        max_drawdown_percent = d.pop("maxDrawdownPercent", UNSET)
154
155        live_paper_kpi = cls(
156            total_trades=total_trades,
157            win_count=win_count,
158            loss_count=loss_count,
159            win_rate=win_rate,
160            pnl_total=pnl_total,
161            pnl_total_percent=pnl_total_percent,
162            sharpe_ratio=sharpe_ratio,
163            sortino_ratio=sortino_ratio,
164            cagr=cagr,
165            max_drawdown=max_drawdown,
166            max_drawdown_percent=max_drawdown_percent,
167        )
168
169        live_paper_kpi.additional_properties = d
170        return live_paper_kpi
171
172    @property
173    def additional_keys(self) -> list[str]:
174        return list(self.additional_properties.keys())
175
176    def __getitem__(self, key: str) -> Any:
177        return self.additional_properties[key]
178
179    def __setitem__(self, key: str, value: Any) -> None:
180        self.additional_properties[key] = value
181
182    def __delitem__(self, key: str) -> None:
183        del self.additional_properties[key]
184
185    def __contains__(self, key: str) -> bool:
186        return key in self.additional_properties

The same KPIs a backtest reports, over the trades closed so far. Absent until the first closed trade is recorded.

Attributes: total_trades (int | Unset): win_count (int | Unset): loss_count (int | Unset): win_rate (float | Unset): Ratio (0.5 = half the trades won). pnl_total (float | Unset): pnl_total_percent (float | Unset): Percent of initialFunding (0-100 scale). sharpe_ratio (float | None | Unset): sortino_ratio (float | None | Unset): cagr (float | None | Unset): Ratio (0.15 for 15%). max_drawdown (float | Unset): max_drawdown_percent (float | Unset): Percent (0-100 scale).

LivePaperKpi( total_trades: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, win_count: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, loss_count: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, win_rate: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, pnl_total: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, pnl_total_percent: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, sharpe_ratio: float | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, sortino_ratio: float | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cagr: float | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, max_drawdown: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, max_drawdown_percent: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
34def __init__(self, total_trades=attr_dict['total_trades'].default, win_count=attr_dict['win_count'].default, loss_count=attr_dict['loss_count'].default, win_rate=attr_dict['win_rate'].default, pnl_total=attr_dict['pnl_total'].default, pnl_total_percent=attr_dict['pnl_total_percent'].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):
35    self.total_trades = total_trades
36    self.win_count = win_count
37    self.loss_count = loss_count
38    self.win_rate = win_rate
39    self.pnl_total = pnl_total
40    self.pnl_total_percent = pnl_total_percent
41    self.sharpe_ratio = sharpe_ratio
42    self.sortino_ratio = sortino_ratio
43    self.cagr = cagr
44    self.max_drawdown = max_drawdown
45    self.max_drawdown_percent = max_drawdown_percent
46    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LivePaperKpi.

total_trades: int | qtsurfer.api.client._generated.types.Unset
win_count: int | qtsurfer.api.client._generated.types.Unset
loss_count: int | qtsurfer.api.client._generated.types.Unset
win_rate: float | qtsurfer.api.client._generated.types.Unset
pnl_total: float | qtsurfer.api.client._generated.types.Unset
pnl_total_percent: float | qtsurfer.api.client._generated.types.Unset
sharpe_ratio: float | None | qtsurfer.api.client._generated.types.Unset
sortino_ratio: float | None | qtsurfer.api.client._generated.types.Unset
cagr: float | None | qtsurfer.api.client._generated.types.Unset
max_drawdown: float | qtsurfer.api.client._generated.types.Unset
max_drawdown_percent: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 46    def to_dict(self) -> dict[str, Any]:
 47        total_trades = self.total_trades
 48
 49        win_count = self.win_count
 50
 51        loss_count = self.loss_count
 52
 53        win_rate = self.win_rate
 54
 55        pnl_total = self.pnl_total
 56
 57        pnl_total_percent = self.pnl_total_percent
 58
 59        sharpe_ratio: float | None | Unset
 60        if isinstance(self.sharpe_ratio, Unset):
 61            sharpe_ratio = UNSET
 62        else:
 63            sharpe_ratio = self.sharpe_ratio
 64
 65        sortino_ratio: float | None | Unset
 66        if isinstance(self.sortino_ratio, Unset):
 67            sortino_ratio = UNSET
 68        else:
 69            sortino_ratio = self.sortino_ratio
 70
 71        cagr: float | None | Unset
 72        if isinstance(self.cagr, Unset):
 73            cagr = UNSET
 74        else:
 75            cagr = self.cagr
 76
 77        max_drawdown = self.max_drawdown
 78
 79        max_drawdown_percent = self.max_drawdown_percent
 80
 81        field_dict: dict[str, Any] = {}
 82        field_dict.update(self.additional_properties)
 83        field_dict.update({})
 84        if total_trades is not UNSET:
 85            field_dict["totalTrades"] = total_trades
 86        if win_count is not UNSET:
 87            field_dict["winCount"] = win_count
 88        if loss_count is not UNSET:
 89            field_dict["lossCount"] = loss_count
 90        if win_rate is not UNSET:
 91            field_dict["winRate"] = win_rate
 92        if pnl_total is not UNSET:
 93            field_dict["pnlTotal"] = pnl_total
 94        if pnl_total_percent is not UNSET:
 95            field_dict["pnlTotalPercent"] = pnl_total_percent
 96        if sharpe_ratio is not UNSET:
 97            field_dict["sharpeRatio"] = sharpe_ratio
 98        if sortino_ratio is not UNSET:
 99            field_dict["sortinoRatio"] = sortino_ratio
100        if cagr is not UNSET:
101            field_dict["cagr"] = cagr
102        if max_drawdown is not UNSET:
103            field_dict["maxDrawdown"] = max_drawdown
104        if max_drawdown_percent is not UNSET:
105            field_dict["maxDrawdownPercent"] = max_drawdown_percent
106
107        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
109    @classmethod
110    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
111        d = dict(src_dict)
112        total_trades = d.pop("totalTrades", UNSET)
113
114        win_count = d.pop("winCount", UNSET)
115
116        loss_count = d.pop("lossCount", UNSET)
117
118        win_rate = d.pop("winRate", UNSET)
119
120        pnl_total = d.pop("pnlTotal", UNSET)
121
122        pnl_total_percent = d.pop("pnlTotalPercent", UNSET)
123
124        def _parse_sharpe_ratio(data: object) -> float | None | Unset:
125            if data is None:
126                return data
127            if isinstance(data, Unset):
128                return data
129            return cast(float | None | Unset, data)
130
131        sharpe_ratio = _parse_sharpe_ratio(d.pop("sharpeRatio", UNSET))
132
133        def _parse_sortino_ratio(data: object) -> float | None | Unset:
134            if data is None:
135                return data
136            if isinstance(data, Unset):
137                return data
138            return cast(float | None | Unset, data)
139
140        sortino_ratio = _parse_sortino_ratio(d.pop("sortinoRatio", UNSET))
141
142        def _parse_cagr(data: object) -> float | None | Unset:
143            if data is None:
144                return data
145            if isinstance(data, Unset):
146                return data
147            return cast(float | None | Unset, data)
148
149        cagr = _parse_cagr(d.pop("cagr", UNSET))
150
151        max_drawdown = d.pop("maxDrawdown", UNSET)
152
153        max_drawdown_percent = d.pop("maxDrawdownPercent", UNSET)
154
155        live_paper_kpi = cls(
156            total_trades=total_trades,
157            win_count=win_count,
158            loss_count=loss_count,
159            win_rate=win_rate,
160            pnl_total=pnl_total,
161            pnl_total_percent=pnl_total_percent,
162            sharpe_ratio=sharpe_ratio,
163            sortino_ratio=sortino_ratio,
164            cagr=cagr,
165            max_drawdown=max_drawdown,
166            max_drawdown_percent=max_drawdown_percent,
167        )
168
169        live_paper_kpi.additional_properties = d
170        return live_paper_kpi
additional_keys: list[str]
172    @property
173    def additional_keys(self) -> list[str]:
174        return list(self.additional_properties.keys())
class LivePaperPosition:
13@_attrs_define
14class LivePaperPosition:
15    """
16    Attributes:
17        instrument (str):  Example: BTC/USDT.
18        base (float): Amount held, in the base asset.
19        cost (float): What it cost, in the account's currency.
20    """
21
22    instrument: str
23    base: float
24    cost: float
25    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
26
27    def to_dict(self) -> dict[str, Any]:
28        instrument = self.instrument
29
30        base = self.base
31
32        cost = self.cost
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "instrument": instrument,
39                "base": base,
40                "cost": cost,
41            }
42        )
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        instrument = d.pop("instrument")
50
51        base = d.pop("base")
52
53        cost = d.pop("cost")
54
55        live_paper_position = cls(
56            instrument=instrument,
57            base=base,
58            cost=cost,
59        )
60
61        live_paper_position.additional_properties = d
62        return live_paper_position
63
64    @property
65    def additional_keys(self) -> list[str]:
66        return list(self.additional_properties.keys())
67
68    def __getitem__(self, key: str) -> Any:
69        return self.additional_properties[key]
70
71    def __setitem__(self, key: str, value: Any) -> None:
72        self.additional_properties[key] = value
73
74    def __delitem__(self, key: str) -> None:
75        del self.additional_properties[key]
76
77    def __contains__(self, key: str) -> bool:
78        return key in self.additional_properties

Attributes: instrument (str): Example: BTC/USDT. base (float): Amount held, in the base asset. cost (float): What it cost, in the account's currency.

LivePaperPosition(instrument: str, base: float, cost: float)
26def __init__(self, instrument, base, cost):
27    self.instrument = instrument
28    self.base = base
29    self.cost = cost
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LivePaperPosition.

instrument: str
base: float
cost: float
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
27    def to_dict(self) -> dict[str, Any]:
28        instrument = self.instrument
29
30        base = self.base
31
32        cost = self.cost
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "instrument": instrument,
39                "base": base,
40                "cost": cost,
41            }
42        )
43
44        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
46    @classmethod
47    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
48        d = dict(src_dict)
49        instrument = d.pop("instrument")
50
51        base = d.pop("base")
52
53        cost = d.pop("cost")
54
55        live_paper_position = cls(
56            instrument=instrument,
57            base=base,
58            cost=cost,
59        )
60
61        live_paper_position.additional_properties = d
62        return live_paper_position
additional_keys: list[str]
64    @property
65    def additional_keys(self) -> list[str]:
66        return list(self.additional_properties.keys())
class LivePaperStage(builtins.str, enum.Enum):
 5class LivePaperStage(str, Enum):
 6    LIVE = "LIVE"
 7    SANDBOX = "SANDBOX"
 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'.

LIVE = <LivePaperStage.LIVE: 'LIVE'>
SANDBOX = <LivePaperStage.SANDBOX: 'SANDBOX'>
class LiveParamsUpdateResult:
13@_attrs_define
14class LiveParamsUpdateResult:
15    """
16    Attributes:
17        run_id (str):
18        params_version (int):
19        effective_at_ms (int): Epoch milliseconds — the earliest moment the new values are guaranteed to be in effect.
20    """
21
22    run_id: str
23    params_version: int
24    effective_at_ms: int
25    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
26
27    def to_dict(self) -> dict[str, Any]:
28        run_id = self.run_id
29
30        params_version = self.params_version
31
32        effective_at_ms = self.effective_at_ms
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "runId": run_id,
39                "paramsVersion": params_version,
40                "effectiveAtMs": effective_at_ms,
41            }
42        )
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        run_id = d.pop("runId")
50
51        params_version = d.pop("paramsVersion")
52
53        effective_at_ms = d.pop("effectiveAtMs")
54
55        live_params_update_result = cls(
56            run_id=run_id,
57            params_version=params_version,
58            effective_at_ms=effective_at_ms,
59        )
60
61        live_params_update_result.additional_properties = d
62        return live_params_update_result
63
64    @property
65    def additional_keys(self) -> list[str]:
66        return list(self.additional_properties.keys())
67
68    def __getitem__(self, key: str) -> Any:
69        return self.additional_properties[key]
70
71    def __setitem__(self, key: str, value: Any) -> None:
72        self.additional_properties[key] = value
73
74    def __delitem__(self, key: str) -> None:
75        del self.additional_properties[key]
76
77    def __contains__(self, key: str) -> bool:
78        return key in self.additional_properties

Attributes: run_id (str): params_version (int): effective_at_ms (int): Epoch milliseconds — the earliest moment the new values are guaranteed to be in effect.

LiveParamsUpdateResult(run_id: str, params_version: int, effective_at_ms: int)
26def __init__(self, run_id, params_version, effective_at_ms):
27    self.run_id = run_id
28    self.params_version = params_version
29    self.effective_at_ms = effective_at_ms
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveParamsUpdateResult.

run_id: str
params_version: int
effective_at_ms: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
27    def to_dict(self) -> dict[str, Any]:
28        run_id = self.run_id
29
30        params_version = self.params_version
31
32        effective_at_ms = self.effective_at_ms
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update(
37            {
38                "runId": run_id,
39                "paramsVersion": params_version,
40                "effectiveAtMs": effective_at_ms,
41            }
42        )
43
44        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
46    @classmethod
47    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
48        d = dict(src_dict)
49        run_id = d.pop("runId")
50
51        params_version = d.pop("paramsVersion")
52
53        effective_at_ms = d.pop("effectiveAtMs")
54
55        live_params_update_result = cls(
56            run_id=run_id,
57            params_version=params_version,
58            effective_at_ms=effective_at_ms,
59        )
60
61        live_params_update_result.additional_properties = d
62        return live_params_update_result
additional_keys: list[str]
64    @property
65    def additional_keys(self) -> list[str]:
66        return list(self.additional_properties.keys())
class LiveRun:
 26@_attrs_define
 27class LiveRun:
 28    """A live run's full state, as returned by stopping it through its strategy, and the base of the representations
 29    returned by starting and by reading it. `warmFrom` is declared by those two (`LiveRunWithStream` and
 30    `LiveRunDetail`) and not here, because the response to stopping a run does not carry it.
 31
 32        Attributes:
 33            strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
 34                always yields the same id, for every caller. How much formatting the id ignores depends on
 35                the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 36                not.
 37                 Example: 6bsh31ikwkuivhtgcoa6s4.
 38            run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
 39                /live/public`.
 40            visibility (LiveRunVisibility):
 41            stage (LiveRunStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a second
 42                execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically when the
 43                24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts `LIVE`,
 44                unless you started it with `sandbox: true`.
 45            state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
 46                (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
 47                for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
 48                signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
 49                `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
 50                running run with something to look at. See the Live execution guide.
 51            desired (LiveRunDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
 52            sources (list[LiveSource]):
 53            params (LiveRunParams):
 54            params_version (int): Increments on every accepted `PUT .../params` call, including one that resends the current
 55                values.
 56            relay (bool): Whether this run's signals are relayed over the WebSocket channel described in the "Live
 57                execution" guide. It is the value requested at start, in either stage.
 58            started_at_ms (int): Epoch milliseconds.
 59            name (str | Unset):
 60            description (str | Unset):
 61            reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
 62                never a
 63                stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
 64                exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
 65                a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
 66                definition was refused, the run could not start after several attempts, the strategy failed while
 67                processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
 68                read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
 69                `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
 70                live-run limit) until then; one that can never run because its strategy cannot consume its source
 71                type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
 72            gate (LiveRunGate | Unset): The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and
 73                present once it ends, so an absent `gate` means the trial has not finished. A run that started in `LIVE` without
 74                a trial has it from the start: the verdict of the earlier run it relies on, with `inheritedFrom` naming that
 75                run. `passed` is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API:
 76                treat it as opaque.
 77            paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's `baseConfig`
 78                (same fields,
 79                defaults and limits), plus `output`. An empty object takes every default. Each quote
 80                currency the run trades gets its own simulated account, opened with `initialFunding` in
 81                that currency; accounts are never added together. As returned on a run, the block is
 82                normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
 83                in.
 84            stats (LiveRunStats | Unset): What a run has been doing, as of its last snapshot. The platform refreshes it
 85                about once a minute
 86                while the run is being executed, so `opsPerSecond` is an average over that interval, not an
 87                instantaneous rate.
 88    """
 89
 90    strategy_id: str
 91    run_id: str
 92    visibility: LiveRunVisibility
 93    stage: LiveRunStage
 94    state: str
 95    desired: LiveRunDesired
 96    sources: list[LiveSource]
 97    params: LiveRunParams
 98    params_version: int
 99    relay: bool
100    started_at_ms: int
101    name: str | Unset = UNSET
102    description: str | Unset = UNSET
103    reason: str | Unset = UNSET
104    gate: LiveRunGate | Unset = UNSET
105    paper: LivePaperConfig | Unset = UNSET
106    stats: LiveRunStats | 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        run_id = self.run_id
113
114        visibility = self.visibility.value
115
116        stage = self.stage.value
117
118        state = self.state
119
120        desired = self.desired.value
121
122        sources = []
123        for sources_item_data in self.sources:
124            sources_item = sources_item_data.to_dict()
125            sources.append(sources_item)
126
127        params = self.params.to_dict()
128
129        params_version = self.params_version
130
131        relay = self.relay
132
133        started_at_ms = self.started_at_ms
134
135        name = self.name
136
137        description = self.description
138
139        reason = self.reason
140
141        gate: dict[str, Any] | Unset = UNSET
142        if not isinstance(self.gate, Unset):
143            gate = self.gate.to_dict()
144
145        paper: dict[str, Any] | Unset = UNSET
146        if not isinstance(self.paper, Unset):
147            paper = self.paper.to_dict()
148
149        stats: dict[str, Any] | Unset = UNSET
150        if not isinstance(self.stats, Unset):
151            stats = self.stats.to_dict()
152
153        field_dict: dict[str, Any] = {}
154        field_dict.update(self.additional_properties)
155        field_dict.update(
156            {
157                "strategyId": strategy_id,
158                "runId": run_id,
159                "visibility": visibility,
160                "stage": stage,
161                "state": state,
162                "desired": desired,
163                "sources": sources,
164                "params": params,
165                "paramsVersion": params_version,
166                "relay": relay,
167                "startedAtMs": started_at_ms,
168            }
169        )
170        if name is not UNSET:
171            field_dict["name"] = name
172        if description is not UNSET:
173            field_dict["description"] = description
174        if reason is not UNSET:
175            field_dict["reason"] = reason
176        if gate is not UNSET:
177            field_dict["gate"] = gate
178        if paper is not UNSET:
179            field_dict["paper"] = paper
180        if stats is not UNSET:
181            field_dict["stats"] = stats
182
183        return field_dict
184
185    @classmethod
186    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
187        from ..models.live_paper_config import LivePaperConfig
188        from ..models.live_run_gate import LiveRunGate
189        from ..models.live_run_params import LiveRunParams
190        from ..models.live_run_stats import LiveRunStats
191        from ..models.live_source import LiveSource
192
193        d = dict(src_dict)
194        strategy_id = d.pop("strategyId")
195
196        run_id = d.pop("runId")
197
198        visibility = LiveRunVisibility(d.pop("visibility"))
199
200        stage = LiveRunStage(d.pop("stage"))
201
202        state = d.pop("state")
203
204        desired = LiveRunDesired(d.pop("desired"))
205
206        sources = []
207        _sources = d.pop("sources")
208        for sources_item_data in _sources:
209            sources_item = LiveSource.from_dict(sources_item_data)
210
211            sources.append(sources_item)
212
213        params = LiveRunParams.from_dict(d.pop("params"))
214
215        params_version = d.pop("paramsVersion")
216
217        relay = d.pop("relay")
218
219        started_at_ms = d.pop("startedAtMs")
220
221        name = d.pop("name", UNSET)
222
223        description = d.pop("description", UNSET)
224
225        reason = d.pop("reason", UNSET)
226
227        _gate = d.pop("gate", UNSET)
228        gate: LiveRunGate | Unset
229        if isinstance(_gate, Unset):
230            gate = UNSET
231        else:
232            gate = LiveRunGate.from_dict(_gate)
233
234        _paper = d.pop("paper", UNSET)
235        paper: LivePaperConfig | Unset
236        if isinstance(_paper, Unset):
237            paper = UNSET
238        else:
239            paper = LivePaperConfig.from_dict(_paper)
240
241        _stats = d.pop("stats", UNSET)
242        stats: LiveRunStats | Unset
243        if isinstance(_stats, Unset):
244            stats = UNSET
245        else:
246            stats = LiveRunStats.from_dict(_stats)
247
248        live_run = cls(
249            strategy_id=strategy_id,
250            run_id=run_id,
251            visibility=visibility,
252            stage=stage,
253            state=state,
254            desired=desired,
255            sources=sources,
256            params=params,
257            params_version=params_version,
258            relay=relay,
259            started_at_ms=started_at_ms,
260            name=name,
261            description=description,
262            reason=reason,
263            gate=gate,
264            paper=paper,
265            stats=stats,
266        )
267
268        live_run.additional_properties = d
269        return live_run
270
271    @property
272    def additional_keys(self) -> list[str]:
273        return list(self.additional_properties.keys())
274
275    def __getitem__(self, key: str) -> Any:
276        return self.additional_properties[key]
277
278    def __setitem__(self, key: str, value: Any) -> None:
279        self.additional_properties[key] = value
280
281    def __delitem__(self, key: str) -> None:
282        del self.additional_properties[key]
283
284    def __contains__(self, key: str) -> bool:
285        return key in self.additional_properties

A live run's full state, as returned by stopping it through its strategy, and the base of the representations returned by starting and by reading it. warmFrom is declared by those two (LiveRunWithStream and LiveRunDetail) and not here, because the response to stopping a run does not carry it.

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. How much formatting the id ignores depends on
        the language — see `POST /strategy` for exactly which rewrites preserve it and which do
        not.
         Example: 6bsh31ikwkuivhtgcoa6s4.
    run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
        /live/public`.
    visibility (LiveRunVisibility):
    stage (LiveRunStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a second
        execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically when the
        24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts `LIVE`,
        unless you started it with `sandbox: true`.
    state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
        (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
        for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
        signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
        `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
        running run with something to look at. See the Live execution guide.
    desired (LiveRunDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
    sources (list[LiveSource]):
    params (LiveRunParams):
    params_version (int): Increments on every accepted `PUT .../params` call, including one that resends the current
        values.
    relay (bool): Whether this run's signals are relayed over the WebSocket channel described in the "Live
        execution" guide. It is the value requested at start, in either stage.
    started_at_ms (int): Epoch milliseconds.
    name (str | Unset):
    description (str | Unset):
    reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
        never a
        stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
        exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
        a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
        definition was refused, the run could not start after several attempts, the strategy failed while
        processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
        read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
        `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
        live-run limit) until then; one that can never run because its strategy cannot consume its source
        type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
    gate (LiveRunGate | Unset): The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and
        present once it ends, so an absent `gate` means the trial has not finished. A run that started in `LIVE` without
        a trial has it from the start: the verdict of the earlier run it relies on, with `inheritedFrom` naming that
        run. `passed` is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API:
        treat it as opaque.
    paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's `baseConfig`
        (same fields,
        defaults and limits), plus `output`. An empty object takes every default. Each quote
        currency the run trades gets its own simulated account, opened with `initialFunding` in
        that currency; accounts are never added together. As returned on a run, the block is
        normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
        in.
    stats (LiveRunStats | Unset): What a run has been doing, as of its last snapshot. The platform refreshes it
        about once a minute
        while the run is being executed, so `opsPerSecond` is an average over that interval, not an
        instantaneous rate.
LiveRun( strategy_id: str, run_id: str, visibility: LiveRunVisibility, stage: LiveRunStage, state: str, desired: LiveRunDesired, sources: list[LiveSource], params: LiveRunParams, params_version: int, relay: bool, started_at_ms: int, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, reason: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, gate: LiveRunGate | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, stats: LiveRunStats | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
40def __init__(self, strategy_id, run_id, visibility, stage, state, desired, sources, params, params_version, relay, started_at_ms, name=attr_dict['name'].default, description=attr_dict['description'].default, reason=attr_dict['reason'].default, gate=attr_dict['gate'].default, paper=attr_dict['paper'].default, stats=attr_dict['stats'].default):
41    self.strategy_id = strategy_id
42    self.run_id = run_id
43    self.visibility = visibility
44    self.stage = stage
45    self.state = state
46    self.desired = desired
47    self.sources = sources
48    self.params = params
49    self.params_version = params_version
50    self.relay = relay
51    self.started_at_ms = started_at_ms
52    self.name = name
53    self.description = description
54    self.reason = reason
55    self.gate = gate
56    self.paper = paper
57    self.stats = stats
58    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRun.

strategy_id: str
run_id: str
visibility: LiveRunVisibility
stage: LiveRunStage
state: str
desired: LiveRunDesired
sources: list[LiveSource]
params: LiveRunParams
params_version: int
relay: bool
started_at_ms: int
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
reason: str | qtsurfer.api.client._generated.types.Unset
gate: LiveRunGate | qtsurfer.api.client._generated.types.Unset
paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset
stats: LiveRunStats | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
109    def to_dict(self) -> dict[str, Any]:
110        strategy_id = self.strategy_id
111
112        run_id = self.run_id
113
114        visibility = self.visibility.value
115
116        stage = self.stage.value
117
118        state = self.state
119
120        desired = self.desired.value
121
122        sources = []
123        for sources_item_data in self.sources:
124            sources_item = sources_item_data.to_dict()
125            sources.append(sources_item)
126
127        params = self.params.to_dict()
128
129        params_version = self.params_version
130
131        relay = self.relay
132
133        started_at_ms = self.started_at_ms
134
135        name = self.name
136
137        description = self.description
138
139        reason = self.reason
140
141        gate: dict[str, Any] | Unset = UNSET
142        if not isinstance(self.gate, Unset):
143            gate = self.gate.to_dict()
144
145        paper: dict[str, Any] | Unset = UNSET
146        if not isinstance(self.paper, Unset):
147            paper = self.paper.to_dict()
148
149        stats: dict[str, Any] | Unset = UNSET
150        if not isinstance(self.stats, Unset):
151            stats = self.stats.to_dict()
152
153        field_dict: dict[str, Any] = {}
154        field_dict.update(self.additional_properties)
155        field_dict.update(
156            {
157                "strategyId": strategy_id,
158                "runId": run_id,
159                "visibility": visibility,
160                "stage": stage,
161                "state": state,
162                "desired": desired,
163                "sources": sources,
164                "params": params,
165                "paramsVersion": params_version,
166                "relay": relay,
167                "startedAtMs": started_at_ms,
168            }
169        )
170        if name is not UNSET:
171            field_dict["name"] = name
172        if description is not UNSET:
173            field_dict["description"] = description
174        if reason is not UNSET:
175            field_dict["reason"] = reason
176        if gate is not UNSET:
177            field_dict["gate"] = gate
178        if paper is not UNSET:
179            field_dict["paper"] = paper
180        if stats is not UNSET:
181            field_dict["stats"] = stats
182
183        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
185    @classmethod
186    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
187        from ..models.live_paper_config import LivePaperConfig
188        from ..models.live_run_gate import LiveRunGate
189        from ..models.live_run_params import LiveRunParams
190        from ..models.live_run_stats import LiveRunStats
191        from ..models.live_source import LiveSource
192
193        d = dict(src_dict)
194        strategy_id = d.pop("strategyId")
195
196        run_id = d.pop("runId")
197
198        visibility = LiveRunVisibility(d.pop("visibility"))
199
200        stage = LiveRunStage(d.pop("stage"))
201
202        state = d.pop("state")
203
204        desired = LiveRunDesired(d.pop("desired"))
205
206        sources = []
207        _sources = d.pop("sources")
208        for sources_item_data in _sources:
209            sources_item = LiveSource.from_dict(sources_item_data)
210
211            sources.append(sources_item)
212
213        params = LiveRunParams.from_dict(d.pop("params"))
214
215        params_version = d.pop("paramsVersion")
216
217        relay = d.pop("relay")
218
219        started_at_ms = d.pop("startedAtMs")
220
221        name = d.pop("name", UNSET)
222
223        description = d.pop("description", UNSET)
224
225        reason = d.pop("reason", UNSET)
226
227        _gate = d.pop("gate", UNSET)
228        gate: LiveRunGate | Unset
229        if isinstance(_gate, Unset):
230            gate = UNSET
231        else:
232            gate = LiveRunGate.from_dict(_gate)
233
234        _paper = d.pop("paper", UNSET)
235        paper: LivePaperConfig | Unset
236        if isinstance(_paper, Unset):
237            paper = UNSET
238        else:
239            paper = LivePaperConfig.from_dict(_paper)
240
241        _stats = d.pop("stats", UNSET)
242        stats: LiveRunStats | Unset
243        if isinstance(_stats, Unset):
244            stats = UNSET
245        else:
246            stats = LiveRunStats.from_dict(_stats)
247
248        live_run = cls(
249            strategy_id=strategy_id,
250            run_id=run_id,
251            visibility=visibility,
252            stage=stage,
253            state=state,
254            desired=desired,
255            sources=sources,
256            params=params,
257            params_version=params_version,
258            relay=relay,
259            started_at_ms=started_at_ms,
260            name=name,
261            description=description,
262            reason=reason,
263            gate=gate,
264            paper=paper,
265            stats=stats,
266        )
267
268        live_run.additional_properties = d
269        return live_run
additional_keys: list[str]
271    @property
272    def additional_keys(self) -> list[str]:
273        return list(self.additional_properties.keys())
class LiveRunCompact:
 21@_attrs_define
 22class LiveRunCompact:
 23    """A run's state as returned by `PATCH /live/{runId}` — narrower than `LiveRun` (no `strategyId`, `params`, or
 24    `desired`), since this endpoint is addressed by `runId` alone.
 25
 26        Attributes:
 27            run_id (str):
 28            visibility (LiveRunCompactVisibility):
 29            stage (LiveRunCompactStage):
 30            state (str):
 31            sources (list[LiveSource]):
 32            name (str | Unset):
 33            description (str | Unset):
 34    """
 35
 36    run_id: str
 37    visibility: LiveRunCompactVisibility
 38    stage: LiveRunCompactStage
 39    state: str
 40    sources: list[LiveSource]
 41    name: str | Unset = UNSET
 42    description: str | Unset = UNSET
 43    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 44
 45    def to_dict(self) -> dict[str, Any]:
 46        run_id = self.run_id
 47
 48        visibility = self.visibility.value
 49
 50        stage = self.stage.value
 51
 52        state = self.state
 53
 54        sources = []
 55        for sources_item_data in self.sources:
 56            sources_item = sources_item_data.to_dict()
 57            sources.append(sources_item)
 58
 59        name = self.name
 60
 61        description = self.description
 62
 63        field_dict: dict[str, Any] = {}
 64        field_dict.update(self.additional_properties)
 65        field_dict.update(
 66            {
 67                "runId": run_id,
 68                "visibility": visibility,
 69                "stage": stage,
 70                "state": state,
 71                "sources": sources,
 72            }
 73        )
 74        if name is not UNSET:
 75            field_dict["name"] = name
 76        if description is not UNSET:
 77            field_dict["description"] = description
 78
 79        return field_dict
 80
 81    @classmethod
 82    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 83        from ..models.live_source import LiveSource
 84
 85        d = dict(src_dict)
 86        run_id = d.pop("runId")
 87
 88        visibility = LiveRunCompactVisibility(d.pop("visibility"))
 89
 90        stage = LiveRunCompactStage(d.pop("stage"))
 91
 92        state = d.pop("state")
 93
 94        sources = []
 95        _sources = d.pop("sources")
 96        for sources_item_data in _sources:
 97            sources_item = LiveSource.from_dict(sources_item_data)
 98
 99            sources.append(sources_item)
100
101        name = d.pop("name", UNSET)
102
103        description = d.pop("description", UNSET)
104
105        live_run_compact = cls(
106            run_id=run_id,
107            visibility=visibility,
108            stage=stage,
109            state=state,
110            sources=sources,
111            name=name,
112            description=description,
113        )
114
115        live_run_compact.additional_properties = d
116        return live_run_compact
117
118    @property
119    def additional_keys(self) -> list[str]:
120        return list(self.additional_properties.keys())
121
122    def __getitem__(self, key: str) -> Any:
123        return self.additional_properties[key]
124
125    def __setitem__(self, key: str, value: Any) -> None:
126        self.additional_properties[key] = value
127
128    def __delitem__(self, key: str) -> None:
129        del self.additional_properties[key]
130
131    def __contains__(self, key: str) -> bool:
132        return key in self.additional_properties

A run's state as returned by PATCH /live/{runId} — narrower than LiveRun (no strategyId, params, or desired), since this endpoint is addressed by runId alone.

Attributes:
    run_id (str):
    visibility (LiveRunCompactVisibility):
    stage (LiveRunCompactStage):
    state (str):
    sources (list[LiveSource]):
    name (str | Unset):
    description (str | Unset):
LiveRunCompact( run_id: str, visibility: LiveRunCompactVisibility, stage: LiveRunCompactStage, state: str, sources: list[LiveSource], name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
30def __init__(self, run_id, visibility, stage, state, sources, name=attr_dict['name'].default, description=attr_dict['description'].default):
31    self.run_id = run_id
32    self.visibility = visibility
33    self.stage = stage
34    self.state = state
35    self.sources = sources
36    self.name = name
37    self.description = description
38    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunCompact.

run_id: str
state: str
sources: list[LiveSource]
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
45    def to_dict(self) -> dict[str, Any]:
46        run_id = self.run_id
47
48        visibility = self.visibility.value
49
50        stage = self.stage.value
51
52        state = self.state
53
54        sources = []
55        for sources_item_data in self.sources:
56            sources_item = sources_item_data.to_dict()
57            sources.append(sources_item)
58
59        name = self.name
60
61        description = self.description
62
63        field_dict: dict[str, Any] = {}
64        field_dict.update(self.additional_properties)
65        field_dict.update(
66            {
67                "runId": run_id,
68                "visibility": visibility,
69                "stage": stage,
70                "state": state,
71                "sources": sources,
72            }
73        )
74        if name is not UNSET:
75            field_dict["name"] = name
76        if description is not UNSET:
77            field_dict["description"] = description
78
79        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 81    @classmethod
 82    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 83        from ..models.live_source import LiveSource
 84
 85        d = dict(src_dict)
 86        run_id = d.pop("runId")
 87
 88        visibility = LiveRunCompactVisibility(d.pop("visibility"))
 89
 90        stage = LiveRunCompactStage(d.pop("stage"))
 91
 92        state = d.pop("state")
 93
 94        sources = []
 95        _sources = d.pop("sources")
 96        for sources_item_data in _sources:
 97            sources_item = LiveSource.from_dict(sources_item_data)
 98
 99            sources.append(sources_item)
100
101        name = d.pop("name", UNSET)
102
103        description = d.pop("description", UNSET)
104
105        live_run_compact = cls(
106            run_id=run_id,
107            visibility=visibility,
108            stage=stage,
109            state=state,
110            sources=sources,
111            name=name,
112            description=description,
113        )
114
115        live_run_compact.additional_properties = d
116        return live_run_compact
additional_keys: list[str]
118    @property
119    def additional_keys(self) -> list[str]:
120        return list(self.additional_properties.keys())
class LiveRunCompactStage(builtins.str, enum.Enum):
 5class LiveRunCompactStage(str, Enum):
 6    LIVE = "LIVE"
 7    SANDBOX = "SANDBOX"
 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'.

LIVE = <LiveRunCompactStage.LIVE: 'LIVE'>
SANDBOX = <LiveRunCompactStage.SANDBOX: 'SANDBOX'>
class LiveRunCompactVisibility(builtins.str, enum.Enum):
 5class LiveRunCompactVisibility(str, Enum):
 6    PRIVATE = "private"
 7    PUBLIC = "public"
 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'.

PRIVATE = <LiveRunCompactVisibility.PRIVATE: 'private'>
PUBLIC = <LiveRunCompactVisibility.PUBLIC: 'public'>
class LiveRunDesired(builtins.str, enum.Enum):
 5class LiveRunDesired(str, Enum):
 6    RUNNING = "RUNNING"
 7    STOPPED = "STOPPED"
 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'.

RUNNING = <LiveRunDesired.RUNNING: 'RUNNING'>
STOPPED = <LiveRunDesired.STOPPED: 'STOPPED'>
class LiveRunDetail:
 26@_attrs_define
 27class LiveRunDetail:
 28    """A run as returned by `GET /live/{runId}`, the full state of `LiveRun` plus when it last changed.
 29
 30    Attributes:
 31        strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
 32            always yields the same id, for every caller. How much formatting the id ignores depends on
 33            the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 34            not.
 35             Example: 6bsh31ikwkuivhtgcoa6s4.
 36        run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
 37            /live/public`.
 38        visibility (LiveRunVisibility):
 39        stage (LiveRunStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a second
 40            execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically when the
 41            24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts `LIVE`,
 42            unless you started it with `sandbox: true`.
 43        state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
 44            (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
 45            for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
 46            signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
 47            `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
 48            running run with something to look at. See the Live execution guide.
 49        desired (LiveRunDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
 50        sources (list[LiveSource]):
 51        params (LiveRunParams):
 52        params_version (int): Increments on every accepted `PUT .../params` call, including one that resends the current
 53            values.
 54        relay (bool): Whether this run's signals are relayed over the WebSocket channel described in the "Live
 55            execution" guide. It is the value requested at start, in either stage.
 56        started_at_ms (int): Epoch milliseconds.
 57        updated_at_ms (int): Epoch milliseconds of the run's last change, from any cause. It only moves forward, so of
 58            two reads of the same run the one with the larger value is the newer.
 59        name (str | Unset):
 60        description (str | Unset):
 61        reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
 62            never a
 63            stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
 64            exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
 65            a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
 66            definition was refused, the run could not start after several attempts, the strategy failed while
 67            processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
 68            read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
 69            `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
 70            live-run limit) until then; one that can never run because its strategy cannot consume its source
 71            type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
 72        gate (LiveRunGate | Unset): The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and
 73            present once it ends, so an absent `gate` means the trial has not finished. A run that started in `LIVE` without
 74            a trial has it from the start: the verdict of the earlier run it relies on, with `inheritedFrom` naming that
 75            run. `passed` is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API:
 76            treat it as opaque.
 77        paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's `baseConfig`
 78            (same fields,
 79            defaults and limits), plus `output`. An empty object takes every default. Each quote
 80            currency the run trades gets its own simulated account, opened with `initialFunding` in
 81            that currency; accounts are never added together. As returned on a run, the block is
 82            normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
 83            in.
 84        stats (LiveRunStats | Unset): What a run has been doing, as of its last snapshot. The platform refreshes it
 85            about once a minute
 86            while the run is being executed, so `opsPerSecond` is an average over that interval, not an
 87            instantaneous rate.
 88        warm_from (int | Unset): The `warmFrom` in effect for this run, in seconds: the one requested when the run was
 89            started or, when none was, the one the platform chose (the distance from the run's start back to the start of
 90            the current 15-minute block, 0 to 900). It is never `null`. It is present on every run started since the field
 91            exists and absent from a run started before it existed. It never changes while the run exists.
 92    """
 93
 94    strategy_id: str
 95    run_id: str
 96    visibility: LiveRunVisibility
 97    stage: LiveRunStage
 98    state: str
 99    desired: LiveRunDesired
100    sources: list[LiveSource]
101    params: LiveRunParams
102    params_version: int
103    relay: bool
104    started_at_ms: int
105    updated_at_ms: int
106    name: str | Unset = UNSET
107    description: str | Unset = UNSET
108    reason: str | Unset = UNSET
109    gate: LiveRunGate | Unset = UNSET
110    paper: LivePaperConfig | Unset = UNSET
111    stats: LiveRunStats | Unset = UNSET
112    warm_from: int | Unset = UNSET
113    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
114
115    def to_dict(self) -> dict[str, Any]:
116        strategy_id = self.strategy_id
117
118        run_id = self.run_id
119
120        visibility = self.visibility.value
121
122        stage = self.stage.value
123
124        state = self.state
125
126        desired = self.desired.value
127
128        sources = []
129        for sources_item_data in self.sources:
130            sources_item = sources_item_data.to_dict()
131            sources.append(sources_item)
132
133        params = self.params.to_dict()
134
135        params_version = self.params_version
136
137        relay = self.relay
138
139        started_at_ms = self.started_at_ms
140
141        updated_at_ms = self.updated_at_ms
142
143        name = self.name
144
145        description = self.description
146
147        reason = self.reason
148
149        gate: dict[str, Any] | Unset = UNSET
150        if not isinstance(self.gate, Unset):
151            gate = self.gate.to_dict()
152
153        paper: dict[str, Any] | Unset = UNSET
154        if not isinstance(self.paper, Unset):
155            paper = self.paper.to_dict()
156
157        stats: dict[str, Any] | Unset = UNSET
158        if not isinstance(self.stats, Unset):
159            stats = self.stats.to_dict()
160
161        warm_from = self.warm_from
162
163        field_dict: dict[str, Any] = {}
164        field_dict.update(self.additional_properties)
165        field_dict.update(
166            {
167                "strategyId": strategy_id,
168                "runId": run_id,
169                "visibility": visibility,
170                "stage": stage,
171                "state": state,
172                "desired": desired,
173                "sources": sources,
174                "params": params,
175                "paramsVersion": params_version,
176                "relay": relay,
177                "startedAtMs": started_at_ms,
178                "updatedAtMs": updated_at_ms,
179            }
180        )
181        if name is not UNSET:
182            field_dict["name"] = name
183        if description is not UNSET:
184            field_dict["description"] = description
185        if reason is not UNSET:
186            field_dict["reason"] = reason
187        if gate is not UNSET:
188            field_dict["gate"] = gate
189        if paper is not UNSET:
190            field_dict["paper"] = paper
191        if stats is not UNSET:
192            field_dict["stats"] = stats
193        if warm_from is not UNSET:
194            field_dict["warmFrom"] = warm_from
195
196        return field_dict
197
198    @classmethod
199    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
200        from ..models.live_paper_config import LivePaperConfig
201        from ..models.live_run_gate import LiveRunGate
202        from ..models.live_run_params import LiveRunParams
203        from ..models.live_run_stats import LiveRunStats
204        from ..models.live_source import LiveSource
205
206        d = dict(src_dict)
207        strategy_id = d.pop("strategyId")
208
209        run_id = d.pop("runId")
210
211        visibility = LiveRunVisibility(d.pop("visibility"))
212
213        stage = LiveRunStage(d.pop("stage"))
214
215        state = d.pop("state")
216
217        desired = LiveRunDesired(d.pop("desired"))
218
219        sources = []
220        _sources = d.pop("sources")
221        for sources_item_data in _sources:
222            sources_item = LiveSource.from_dict(sources_item_data)
223
224            sources.append(sources_item)
225
226        params = LiveRunParams.from_dict(d.pop("params"))
227
228        params_version = d.pop("paramsVersion")
229
230        relay = d.pop("relay")
231
232        started_at_ms = d.pop("startedAtMs")
233
234        updated_at_ms = d.pop("updatedAtMs")
235
236        name = d.pop("name", UNSET)
237
238        description = d.pop("description", UNSET)
239
240        reason = d.pop("reason", UNSET)
241
242        _gate = d.pop("gate", UNSET)
243        gate: LiveRunGate | Unset
244        if isinstance(_gate, Unset):
245            gate = UNSET
246        else:
247            gate = LiveRunGate.from_dict(_gate)
248
249        _paper = d.pop("paper", UNSET)
250        paper: LivePaperConfig | Unset
251        if isinstance(_paper, Unset):
252            paper = UNSET
253        else:
254            paper = LivePaperConfig.from_dict(_paper)
255
256        _stats = d.pop("stats", UNSET)
257        stats: LiveRunStats | Unset
258        if isinstance(_stats, Unset):
259            stats = UNSET
260        else:
261            stats = LiveRunStats.from_dict(_stats)
262
263        warm_from = d.pop("warmFrom", UNSET)
264
265        live_run_detail = cls(
266            strategy_id=strategy_id,
267            run_id=run_id,
268            visibility=visibility,
269            stage=stage,
270            state=state,
271            desired=desired,
272            sources=sources,
273            params=params,
274            params_version=params_version,
275            relay=relay,
276            started_at_ms=started_at_ms,
277            updated_at_ms=updated_at_ms,
278            name=name,
279            description=description,
280            reason=reason,
281            gate=gate,
282            paper=paper,
283            stats=stats,
284            warm_from=warm_from,
285        )
286
287        live_run_detail.additional_properties = d
288        return live_run_detail
289
290    @property
291    def additional_keys(self) -> list[str]:
292        return list(self.additional_properties.keys())
293
294    def __getitem__(self, key: str) -> Any:
295        return self.additional_properties[key]
296
297    def __setitem__(self, key: str, value: Any) -> None:
298        self.additional_properties[key] = value
299
300    def __delitem__(self, key: str) -> None:
301        del self.additional_properties[key]
302
303    def __contains__(self, key: str) -> bool:
304        return key in self.additional_properties

A run as returned by GET /live/{runId}, the full state of LiveRun plus when it last changed.

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. How much formatting the id ignores depends on the language — see POST /strategy for exactly which rewrites preserve it and which do not. Example: 6bsh31ikwkuivhtgcoa6s4. run_id (str): This run's own id — its canonical identity for PATCH/PUT .../params and for GET /live/public. visibility (LiveRunVisibility): stage (LiveRunStage): A new run starts SANDBOX, a 24-hour trial in which it is compared against a second execution and checked for resource use and stability. A run that passes moves to LIVE automatically when the 24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts LIVE, unless you started it with sandbox: true. state (str): The run's health right now: STARTING (no runner has reported on it yet), RUNNING, LAGGING (behind the market data, usually while catching up; clears by itself), HUNG (stuck inside one strategy call for longer than allowed; clears when it returns), DEGRADED (its independent executions produced different signals), FAILED (refused, could not start or failed while running; reason says why) or STOPPED. LAGGING, HUNG and DEGRADED come and go on a running run. The set may grow: read an unknown value as a running run with something to look at. See the Live execution guide. desired (LiveRunDesired): What you last asked for. state can lag this briefly after DELETE. sources (list[LiveSource]): params (LiveRunParams): params_version (int): Increments on every accepted PUT .../params call, including one that resends the current values. relay (bool): Whether this run's signals are relayed over the WebSocket channel described in the "Live execution" guide. It is the value requested at start, in either stage. started_at_ms (int): Epoch milliseconds. updated_at_ms (int): Epoch milliseconds of the run's last change, from any cause. It only moves forward, so of two reads of the same run the one with the larger value is the newer. name (str | Unset): description (str | Unset): reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is never a stack trace or an internal message. Either resource: ... (the platform stopped the run for exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for a FAILED run: the strategy cannot consume the source type the run was started with, the run's definition was refused, the run could not start after several attempts, the strategy failed while processing data, the run lost its data feed, or the generic The run failed.. The set may grow: read an unrecognised sentence as a failure and do not parse it. A FAILED run usually stays desired: RUNNING until you stop it, and counts as active (409 on a new start, and toward your live-run limit) until then; one that can never run because its strategy cannot consume its source type is stopped by the platform itself (desired: STOPPED), so it holds no place. gate (LiveRunGate | Unset): The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and present once it ends, so an absent gate means the trial has not finished. A run that started in LIVE without a trial has it from the start: the verdict of the earlier run it relies on, with inheritedFrom naming that run. passed is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API: treat it as opaque. paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's baseConfig (same fields, defaults and limits), plus output. An empty object takes every default. Each quote currency the run trades gets its own simulated account, opened with initialFunding in that currency; accounts are never added together. As returned on a run, the block is normalised: feeRate is resolved into buyFeeRate/sellFeeRate and defaults are filled in. stats (LiveRunStats | Unset): What a run has been doing, as of its last snapshot. The platform refreshes it about once a minute while the run is being executed, so opsPerSecond is an average over that interval, not an instantaneous rate. warm_from (int | Unset): The warmFrom in effect for this run, in seconds: the one requested when the run was started or, when none was, the one the platform chose (the distance from the run's start back to the start of the current 15-minute block, 0 to 900). It is never null. It is present on every run started since the field exists and absent from a run started before it existed. It never changes while the run exists.

LiveRunDetail( strategy_id: str, run_id: str, visibility: LiveRunVisibility, stage: LiveRunStage, state: str, desired: LiveRunDesired, sources: list[LiveSource], params: LiveRunParams, params_version: int, relay: bool, started_at_ms: int, updated_at_ms: int, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, reason: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, gate: LiveRunGate | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, stats: LiveRunStats | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, warm_from: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
42def __init__(self, strategy_id, run_id, visibility, stage, state, desired, sources, params, params_version, relay, started_at_ms, updated_at_ms, name=attr_dict['name'].default, description=attr_dict['description'].default, reason=attr_dict['reason'].default, gate=attr_dict['gate'].default, paper=attr_dict['paper'].default, stats=attr_dict['stats'].default, warm_from=attr_dict['warm_from'].default):
43    self.strategy_id = strategy_id
44    self.run_id = run_id
45    self.visibility = visibility
46    self.stage = stage
47    self.state = state
48    self.desired = desired
49    self.sources = sources
50    self.params = params
51    self.params_version = params_version
52    self.relay = relay
53    self.started_at_ms = started_at_ms
54    self.updated_at_ms = updated_at_ms
55    self.name = name
56    self.description = description
57    self.reason = reason
58    self.gate = gate
59    self.paper = paper
60    self.stats = stats
61    self.warm_from = warm_from
62    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunDetail.

strategy_id: str
run_id: str
visibility: LiveRunVisibility
stage: LiveRunStage
state: str
desired: LiveRunDesired
sources: list[LiveSource]
params: LiveRunParams
params_version: int
relay: bool
started_at_ms: int
updated_at_ms: int
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
reason: str | qtsurfer.api.client._generated.types.Unset
gate: LiveRunGate | qtsurfer.api.client._generated.types.Unset
paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset
stats: LiveRunStats | qtsurfer.api.client._generated.types.Unset
warm_from: int | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
115    def to_dict(self) -> dict[str, Any]:
116        strategy_id = self.strategy_id
117
118        run_id = self.run_id
119
120        visibility = self.visibility.value
121
122        stage = self.stage.value
123
124        state = self.state
125
126        desired = self.desired.value
127
128        sources = []
129        for sources_item_data in self.sources:
130            sources_item = sources_item_data.to_dict()
131            sources.append(sources_item)
132
133        params = self.params.to_dict()
134
135        params_version = self.params_version
136
137        relay = self.relay
138
139        started_at_ms = self.started_at_ms
140
141        updated_at_ms = self.updated_at_ms
142
143        name = self.name
144
145        description = self.description
146
147        reason = self.reason
148
149        gate: dict[str, Any] | Unset = UNSET
150        if not isinstance(self.gate, Unset):
151            gate = self.gate.to_dict()
152
153        paper: dict[str, Any] | Unset = UNSET
154        if not isinstance(self.paper, Unset):
155            paper = self.paper.to_dict()
156
157        stats: dict[str, Any] | Unset = UNSET
158        if not isinstance(self.stats, Unset):
159            stats = self.stats.to_dict()
160
161        warm_from = self.warm_from
162
163        field_dict: dict[str, Any] = {}
164        field_dict.update(self.additional_properties)
165        field_dict.update(
166            {
167                "strategyId": strategy_id,
168                "runId": run_id,
169                "visibility": visibility,
170                "stage": stage,
171                "state": state,
172                "desired": desired,
173                "sources": sources,
174                "params": params,
175                "paramsVersion": params_version,
176                "relay": relay,
177                "startedAtMs": started_at_ms,
178                "updatedAtMs": updated_at_ms,
179            }
180        )
181        if name is not UNSET:
182            field_dict["name"] = name
183        if description is not UNSET:
184            field_dict["description"] = description
185        if reason is not UNSET:
186            field_dict["reason"] = reason
187        if gate is not UNSET:
188            field_dict["gate"] = gate
189        if paper is not UNSET:
190            field_dict["paper"] = paper
191        if stats is not UNSET:
192            field_dict["stats"] = stats
193        if warm_from is not UNSET:
194            field_dict["warmFrom"] = warm_from
195
196        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
198    @classmethod
199    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
200        from ..models.live_paper_config import LivePaperConfig
201        from ..models.live_run_gate import LiveRunGate
202        from ..models.live_run_params import LiveRunParams
203        from ..models.live_run_stats import LiveRunStats
204        from ..models.live_source import LiveSource
205
206        d = dict(src_dict)
207        strategy_id = d.pop("strategyId")
208
209        run_id = d.pop("runId")
210
211        visibility = LiveRunVisibility(d.pop("visibility"))
212
213        stage = LiveRunStage(d.pop("stage"))
214
215        state = d.pop("state")
216
217        desired = LiveRunDesired(d.pop("desired"))
218
219        sources = []
220        _sources = d.pop("sources")
221        for sources_item_data in _sources:
222            sources_item = LiveSource.from_dict(sources_item_data)
223
224            sources.append(sources_item)
225
226        params = LiveRunParams.from_dict(d.pop("params"))
227
228        params_version = d.pop("paramsVersion")
229
230        relay = d.pop("relay")
231
232        started_at_ms = d.pop("startedAtMs")
233
234        updated_at_ms = d.pop("updatedAtMs")
235
236        name = d.pop("name", UNSET)
237
238        description = d.pop("description", UNSET)
239
240        reason = d.pop("reason", UNSET)
241
242        _gate = d.pop("gate", UNSET)
243        gate: LiveRunGate | Unset
244        if isinstance(_gate, Unset):
245            gate = UNSET
246        else:
247            gate = LiveRunGate.from_dict(_gate)
248
249        _paper = d.pop("paper", UNSET)
250        paper: LivePaperConfig | Unset
251        if isinstance(_paper, Unset):
252            paper = UNSET
253        else:
254            paper = LivePaperConfig.from_dict(_paper)
255
256        _stats = d.pop("stats", UNSET)
257        stats: LiveRunStats | Unset
258        if isinstance(_stats, Unset):
259            stats = UNSET
260        else:
261            stats = LiveRunStats.from_dict(_stats)
262
263        warm_from = d.pop("warmFrom", UNSET)
264
265        live_run_detail = cls(
266            strategy_id=strategy_id,
267            run_id=run_id,
268            visibility=visibility,
269            stage=stage,
270            state=state,
271            desired=desired,
272            sources=sources,
273            params=params,
274            params_version=params_version,
275            relay=relay,
276            started_at_ms=started_at_ms,
277            updated_at_ms=updated_at_ms,
278            name=name,
279            description=description,
280            reason=reason,
281            gate=gate,
282            paper=paper,
283            stats=stats,
284            warm_from=warm_from,
285        )
286
287        live_run_detail.additional_properties = d
288        return live_run_detail
additional_keys: list[str]
290    @property
291    def additional_keys(self) -> list[str]:
292        return list(self.additional_properties.keys())
class LiveRunGate:
13@_attrs_define
14class LiveRunGate:
15    """The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and present once it ends, so an absent
16    `gate` means the trial has not finished. A run that started in `LIVE` without a trial has it from the start: the
17    verdict of the earlier run it relies on, with `inheritedFrom` naming that run. `passed` is the verdict; the rest is
18    diagnostic detail whose shape is not yet stabilized as public API: treat it as opaque.
19
20    """
21
22    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
23
24    def to_dict(self) -> dict[str, Any]:
25
26        field_dict: dict[str, Any] = {}
27        field_dict.update(self.additional_properties)
28
29        return field_dict
30
31    @classmethod
32    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
33        d = dict(src_dict)
34        live_run_gate = cls()
35
36        live_run_gate.additional_properties = d
37        return live_run_gate
38
39    @property
40    def additional_keys(self) -> list[str]:
41        return list(self.additional_properties.keys())
42
43    def __getitem__(self, key: str) -> Any:
44        return self.additional_properties[key]
45
46    def __setitem__(self, key: str, value: Any) -> None:
47        self.additional_properties[key] = value
48
49    def __delitem__(self, key: str) -> None:
50        del self.additional_properties[key]
51
52    def __contains__(self, key: str) -> bool:
53        return key in self.additional_properties

The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and present once it ends, so an absent gate means the trial has not finished. A run that started in LIVE without a trial has it from the start: the verdict of the earlier run it relies on, with inheritedFrom naming that run. passed is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API: treat it as opaque.

LiveRunGate()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunGate.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
24    def to_dict(self) -> dict[str, Any]:
25
26        field_dict: dict[str, Any] = {}
27        field_dict.update(self.additional_properties)
28
29        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
31    @classmethod
32    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
33        d = dict(src_dict)
34        live_run_gate = cls()
35
36        live_run_gate.additional_properties = d
37        return live_run_gate
additional_keys: list[str]
39    @property
40    def additional_keys(self) -> list[str]:
41        return list(self.additional_properties.keys())
class LiveRunParams:
13@_attrs_define
14class LiveRunParams:
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        live_run_params = cls()
30
31        live_run_params.additional_properties = d
32        return live_run_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
LiveRunParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunParams.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
26    @classmethod
27    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
28        d = dict(src_dict)
29        live_run_params = cls()
30
31        live_run_params.additional_properties = d
32        return live_run_params
additional_keys: list[str]
34    @property
35    def additional_keys(self) -> list[str]:
36        return list(self.additional_properties.keys())
class LiveRunStage(builtins.str, enum.Enum):
 5class LiveRunStage(str, Enum):
 6    LIVE = "LIVE"
 7    SANDBOX = "SANDBOX"
 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'.

LIVE = <LiveRunStage.LIVE: 'LIVE'>
SANDBOX = <LiveRunStage.SANDBOX: 'SANDBOX'>
class LiveRunStats:
 15@_attrs_define
 16class LiveRunStats:
 17    """What a run has been doing, as of its last snapshot. The platform refreshes it about once a minute
 18    while the run is being executed, so `opsPerSecond` is an average over that interval, not an
 19    instantaneous rate.
 20
 21        Attributes:
 22            processed (int): Updates of instruments the run has accepted since it started executing. It can start again from
 23                zero if the run is restarted.
 24            ops_per_second (float): Updates accepted per second over the last refresh interval. `0` when none arrived.
 25            instruments_seen (int): How many distinct instruments the run has received an update for.
 26            as_of_ms (int): Epoch milliseconds when these counters were last written.
 27            stale (bool): `true` when the run is meant to be running (`desired` is `RUNNING`) and its counters have not
 28                been refreshed for several refresh intervals: the platform has stopped updating them, which is
 29                worth checking against `state`. `false` otherwise. A run whose `processed` is flat is not stale;
 30                `progressedAtMs` is how to tell it apart.
 31            progressed_at_ms (int | Unset): Epoch milliseconds of the last snapshot in which `processed` had grown. Absent
 32                until the run has
 33                processed anything. A run fed by a source that updates rarely (a funding rate, for example) can
 34                stay flat for hours: that is how such a run behaves, not a fault.
 35    """
 36
 37    processed: int
 38    ops_per_second: float
 39    instruments_seen: int
 40    as_of_ms: int
 41    stale: bool
 42    progressed_at_ms: int | Unset = UNSET
 43    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 44
 45    def to_dict(self) -> dict[str, Any]:
 46        processed = self.processed
 47
 48        ops_per_second = self.ops_per_second
 49
 50        instruments_seen = self.instruments_seen
 51
 52        as_of_ms = self.as_of_ms
 53
 54        stale = self.stale
 55
 56        progressed_at_ms = self.progressed_at_ms
 57
 58        field_dict: dict[str, Any] = {}
 59        field_dict.update(self.additional_properties)
 60        field_dict.update(
 61            {
 62                "processed": processed,
 63                "opsPerSecond": ops_per_second,
 64                "instrumentsSeen": instruments_seen,
 65                "asOfMs": as_of_ms,
 66                "stale": stale,
 67            }
 68        )
 69        if progressed_at_ms is not UNSET:
 70            field_dict["progressedAtMs"] = progressed_at_ms
 71
 72        return field_dict
 73
 74    @classmethod
 75    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 76        d = dict(src_dict)
 77        processed = d.pop("processed")
 78
 79        ops_per_second = d.pop("opsPerSecond")
 80
 81        instruments_seen = d.pop("instrumentsSeen")
 82
 83        as_of_ms = d.pop("asOfMs")
 84
 85        stale = d.pop("stale")
 86
 87        progressed_at_ms = d.pop("progressedAtMs", UNSET)
 88
 89        live_run_stats = cls(
 90            processed=processed,
 91            ops_per_second=ops_per_second,
 92            instruments_seen=instruments_seen,
 93            as_of_ms=as_of_ms,
 94            stale=stale,
 95            progressed_at_ms=progressed_at_ms,
 96        )
 97
 98        live_run_stats.additional_properties = d
 99        return live_run_stats
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

What a run has been doing, as of its last snapshot. The platform refreshes it about once a minute while the run is being executed, so opsPerSecond is an average over that interval, not an instantaneous rate.

Attributes:
    processed (int): Updates of instruments the run has accepted since it started executing. It can start again from
        zero if the run is restarted.
    ops_per_second (float): Updates accepted per second over the last refresh interval. `0` when none arrived.
    instruments_seen (int): How many distinct instruments the run has received an update for.
    as_of_ms (int): Epoch milliseconds when these counters were last written.
    stale (bool): `true` when the run is meant to be running (`desired` is `RUNNING`) and its counters have not
        been refreshed for several refresh intervals: the platform has stopped updating them, which is
        worth checking against `state`. `false` otherwise. A run whose `processed` is flat is not stale;
        `progressedAtMs` is how to tell it apart.
    progressed_at_ms (int | Unset): Epoch milliseconds of the last snapshot in which `processed` had grown. Absent
        until the run has
        processed anything. A run fed by a source that updates rarely (a funding rate, for example) can
        stay flat for hours: that is how such a run behaves, not a fault.
LiveRunStats( processed: int, ops_per_second: float, instruments_seen: int, as_of_ms: int, stale: bool, progressed_at_ms: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
29def __init__(self, processed, ops_per_second, instruments_seen, as_of_ms, stale, progressed_at_ms=attr_dict['progressed_at_ms'].default):
30    self.processed = processed
31    self.ops_per_second = ops_per_second
32    self.instruments_seen = instruments_seen
33    self.as_of_ms = as_of_ms
34    self.stale = stale
35    self.progressed_at_ms = progressed_at_ms
36    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunStats.

processed: int
ops_per_second: float
instruments_seen: int
as_of_ms: int
stale: bool
progressed_at_ms: int | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
45    def to_dict(self) -> dict[str, Any]:
46        processed = self.processed
47
48        ops_per_second = self.ops_per_second
49
50        instruments_seen = self.instruments_seen
51
52        as_of_ms = self.as_of_ms
53
54        stale = self.stale
55
56        progressed_at_ms = self.progressed_at_ms
57
58        field_dict: dict[str, Any] = {}
59        field_dict.update(self.additional_properties)
60        field_dict.update(
61            {
62                "processed": processed,
63                "opsPerSecond": ops_per_second,
64                "instrumentsSeen": instruments_seen,
65                "asOfMs": as_of_ms,
66                "stale": stale,
67            }
68        )
69        if progressed_at_ms is not UNSET:
70            field_dict["progressedAtMs"] = progressed_at_ms
71
72        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
74    @classmethod
75    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
76        d = dict(src_dict)
77        processed = d.pop("processed")
78
79        ops_per_second = d.pop("opsPerSecond")
80
81        instruments_seen = d.pop("instrumentsSeen")
82
83        as_of_ms = d.pop("asOfMs")
84
85        stale = d.pop("stale")
86
87        progressed_at_ms = d.pop("progressedAtMs", UNSET)
88
89        live_run_stats = cls(
90            processed=processed,
91            ops_per_second=ops_per_second,
92            instruments_seen=instruments_seen,
93            as_of_ms=as_of_ms,
94            stale=stale,
95            progressed_at_ms=progressed_at_ms,
96        )
97
98        live_run_stats.additional_properties = d
99        return live_run_stats
additional_keys: list[str]
101    @property
102    def additional_keys(self) -> list[str]:
103        return list(self.additional_properties.keys())
class LiveRunSummary:
 22@_attrs_define
 23class LiveRunSummary:
 24    """A run as it appears in `GET /live` — one of your own, narrower than `LiveRun` (no `params`, `paramsVersion`,
 25    `relay`, or `gate`), since listing stays cheap regardless of how many runs you have. Check a specific run's full
 26    state with `GET /strategy/{strategyId}/live`.
 27
 28        Attributes:
 29            strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
 30                always yields the same id, for every caller. How much formatting the id ignores depends on
 31                the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 32                not.
 33                 Example: 6bsh31ikwkuivhtgcoa6s4.
 34            run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
 35                /live/public`.
 36            visibility (LiveRunSummaryVisibility):
 37            stage (LiveRunSummaryStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a
 38                second execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically
 39                when the 24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts
 40                `LIVE`, unless you started it with `sandbox: true`.
 41            state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
 42                (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
 43                for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
 44                signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
 45                `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
 46                running run with something to look at. See the Live execution guide.
 47            desired (LiveRunSummaryDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
 48            sources (list[LiveSource]):
 49            created_at_ms (int): Epoch milliseconds this run was started.
 50            started_at_ms (int): Epoch milliseconds.
 51            name (str | Unset):
 52            description (str | Unset):
 53            reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
 54                never a
 55                stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
 56                exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
 57                a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
 58                definition was refused, the run could not start after several attempts, the strategy failed while
 59                processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
 60                read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
 61                `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
 62                live-run limit) until then; one that can never run because its strategy cannot consume its source
 63                type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
 64    """
 65
 66    strategy_id: str
 67    run_id: str
 68    visibility: LiveRunSummaryVisibility
 69    stage: LiveRunSummaryStage
 70    state: str
 71    desired: LiveRunSummaryDesired
 72    sources: list[LiveSource]
 73    created_at_ms: int
 74    started_at_ms: int
 75    name: str | Unset = UNSET
 76    description: str | Unset = UNSET
 77    reason: str | Unset = UNSET
 78    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 79
 80    def to_dict(self) -> dict[str, Any]:
 81        strategy_id = self.strategy_id
 82
 83        run_id = self.run_id
 84
 85        visibility = self.visibility.value
 86
 87        stage = self.stage.value
 88
 89        state = self.state
 90
 91        desired = self.desired.value
 92
 93        sources = []
 94        for sources_item_data in self.sources:
 95            sources_item = sources_item_data.to_dict()
 96            sources.append(sources_item)
 97
 98        created_at_ms = self.created_at_ms
 99
100        started_at_ms = self.started_at_ms
101
102        name = self.name
103
104        description = self.description
105
106        reason = self.reason
107
108        field_dict: dict[str, Any] = {}
109        field_dict.update(self.additional_properties)
110        field_dict.update(
111            {
112                "strategyId": strategy_id,
113                "runId": run_id,
114                "visibility": visibility,
115                "stage": stage,
116                "state": state,
117                "desired": desired,
118                "sources": sources,
119                "createdAtMs": created_at_ms,
120                "startedAtMs": started_at_ms,
121            }
122        )
123        if name is not UNSET:
124            field_dict["name"] = name
125        if description is not UNSET:
126            field_dict["description"] = description
127        if reason is not UNSET:
128            field_dict["reason"] = reason
129
130        return field_dict
131
132    @classmethod
133    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
134        from ..models.live_source import LiveSource
135
136        d = dict(src_dict)
137        strategy_id = d.pop("strategyId")
138
139        run_id = d.pop("runId")
140
141        visibility = LiveRunSummaryVisibility(d.pop("visibility"))
142
143        stage = LiveRunSummaryStage(d.pop("stage"))
144
145        state = d.pop("state")
146
147        desired = LiveRunSummaryDesired(d.pop("desired"))
148
149        sources = []
150        _sources = d.pop("sources")
151        for sources_item_data in _sources:
152            sources_item = LiveSource.from_dict(sources_item_data)
153
154            sources.append(sources_item)
155
156        created_at_ms = d.pop("createdAtMs")
157
158        started_at_ms = d.pop("startedAtMs")
159
160        name = d.pop("name", UNSET)
161
162        description = d.pop("description", UNSET)
163
164        reason = d.pop("reason", UNSET)
165
166        live_run_summary = cls(
167            strategy_id=strategy_id,
168            run_id=run_id,
169            visibility=visibility,
170            stage=stage,
171            state=state,
172            desired=desired,
173            sources=sources,
174            created_at_ms=created_at_ms,
175            started_at_ms=started_at_ms,
176            name=name,
177            description=description,
178            reason=reason,
179        )
180
181        live_run_summary.additional_properties = d
182        return live_run_summary
183
184    @property
185    def additional_keys(self) -> list[str]:
186        return list(self.additional_properties.keys())
187
188    def __getitem__(self, key: str) -> Any:
189        return self.additional_properties[key]
190
191    def __setitem__(self, key: str, value: Any) -> None:
192        self.additional_properties[key] = value
193
194    def __delitem__(self, key: str) -> None:
195        del self.additional_properties[key]
196
197    def __contains__(self, key: str) -> bool:
198        return key in self.additional_properties

A run as it appears in GET /live — one of your own, narrower than LiveRun (no params, paramsVersion, relay, or gate), since listing stays cheap regardless of how many runs you have. Check a specific run's full state with GET /strategy/{strategyId}/live.

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. How much formatting the id ignores depends on
        the language — see `POST /strategy` for exactly which rewrites preserve it and which do
        not.
         Example: 6bsh31ikwkuivhtgcoa6s4.
    run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
        /live/public`.
    visibility (LiveRunSummaryVisibility):
    stage (LiveRunSummaryStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a
        second execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically
        when the 24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts
        `LIVE`, unless you started it with `sandbox: true`.
    state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
        (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
        for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
        signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
        `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
        running run with something to look at. See the Live execution guide.
    desired (LiveRunSummaryDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
    sources (list[LiveSource]):
    created_at_ms (int): Epoch milliseconds this run was started.
    started_at_ms (int): Epoch milliseconds.
    name (str | Unset):
    description (str | Unset):
    reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
        never a
        stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
        exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
        a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
        definition was refused, the run could not start after several attempts, the strategy failed while
        processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
        read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
        `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
        live-run limit) until then; one that can never run because its strategy cannot consume its source
        type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
LiveRunSummary( strategy_id: str, run_id: str, visibility: LiveRunSummaryVisibility, stage: LiveRunSummaryStage, state: str, desired: LiveRunSummaryDesired, sources: list[LiveSource], created_at_ms: int, started_at_ms: int, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, reason: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
35def __init__(self, strategy_id, run_id, visibility, stage, state, desired, sources, created_at_ms, started_at_ms, name=attr_dict['name'].default, description=attr_dict['description'].default, reason=attr_dict['reason'].default):
36    self.strategy_id = strategy_id
37    self.run_id = run_id
38    self.visibility = visibility
39    self.stage = stage
40    self.state = state
41    self.desired = desired
42    self.sources = sources
43    self.created_at_ms = created_at_ms
44    self.started_at_ms = started_at_ms
45    self.name = name
46    self.description = description
47    self.reason = reason
48    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunSummary.

strategy_id: str
run_id: str
state: str
sources: list[LiveSource]
created_at_ms: int
started_at_ms: int
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
reason: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 80    def to_dict(self) -> dict[str, Any]:
 81        strategy_id = self.strategy_id
 82
 83        run_id = self.run_id
 84
 85        visibility = self.visibility.value
 86
 87        stage = self.stage.value
 88
 89        state = self.state
 90
 91        desired = self.desired.value
 92
 93        sources = []
 94        for sources_item_data in self.sources:
 95            sources_item = sources_item_data.to_dict()
 96            sources.append(sources_item)
 97
 98        created_at_ms = self.created_at_ms
 99
100        started_at_ms = self.started_at_ms
101
102        name = self.name
103
104        description = self.description
105
106        reason = self.reason
107
108        field_dict: dict[str, Any] = {}
109        field_dict.update(self.additional_properties)
110        field_dict.update(
111            {
112                "strategyId": strategy_id,
113                "runId": run_id,
114                "visibility": visibility,
115                "stage": stage,
116                "state": state,
117                "desired": desired,
118                "sources": sources,
119                "createdAtMs": created_at_ms,
120                "startedAtMs": started_at_ms,
121            }
122        )
123        if name is not UNSET:
124            field_dict["name"] = name
125        if description is not UNSET:
126            field_dict["description"] = description
127        if reason is not UNSET:
128            field_dict["reason"] = reason
129
130        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
132    @classmethod
133    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
134        from ..models.live_source import LiveSource
135
136        d = dict(src_dict)
137        strategy_id = d.pop("strategyId")
138
139        run_id = d.pop("runId")
140
141        visibility = LiveRunSummaryVisibility(d.pop("visibility"))
142
143        stage = LiveRunSummaryStage(d.pop("stage"))
144
145        state = d.pop("state")
146
147        desired = LiveRunSummaryDesired(d.pop("desired"))
148
149        sources = []
150        _sources = d.pop("sources")
151        for sources_item_data in _sources:
152            sources_item = LiveSource.from_dict(sources_item_data)
153
154            sources.append(sources_item)
155
156        created_at_ms = d.pop("createdAtMs")
157
158        started_at_ms = d.pop("startedAtMs")
159
160        name = d.pop("name", UNSET)
161
162        description = d.pop("description", UNSET)
163
164        reason = d.pop("reason", UNSET)
165
166        live_run_summary = cls(
167            strategy_id=strategy_id,
168            run_id=run_id,
169            visibility=visibility,
170            stage=stage,
171            state=state,
172            desired=desired,
173            sources=sources,
174            created_at_ms=created_at_ms,
175            started_at_ms=started_at_ms,
176            name=name,
177            description=description,
178            reason=reason,
179        )
180
181        live_run_summary.additional_properties = d
182        return live_run_summary
additional_keys: list[str]
184    @property
185    def additional_keys(self) -> list[str]:
186        return list(self.additional_properties.keys())
class LiveRunSummaryDesired(builtins.str, enum.Enum):
 5class LiveRunSummaryDesired(str, Enum):
 6    RUNNING = "RUNNING"
 7    STOPPED = "STOPPED"
 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'.

RUNNING = <LiveRunSummaryDesired.RUNNING: 'RUNNING'>
STOPPED = <LiveRunSummaryDesired.STOPPED: 'STOPPED'>
class LiveRunSummaryStage(builtins.str, enum.Enum):
 5class LiveRunSummaryStage(str, Enum):
 6    LIVE = "LIVE"
 7    SANDBOX = "SANDBOX"
 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'.

LIVE = <LiveRunSummaryStage.LIVE: 'LIVE'>
SANDBOX = <LiveRunSummaryStage.SANDBOX: 'SANDBOX'>
class LiveRunSummaryVisibility(builtins.str, enum.Enum):
 5class LiveRunSummaryVisibility(str, Enum):
 6    PRIVATE = "private"
 7    PUBLIC = "public"
 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'.

PRIVATE = <LiveRunSummaryVisibility.PRIVATE: 'private'>
PUBLIC = <LiveRunSummaryVisibility.PUBLIC: 'public'>
class LiveRunVisibility(builtins.str, enum.Enum):
 5class LiveRunVisibility(str, Enum):
 6    PRIVATE = "private"
 7    PUBLIC = "public"
 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'.

PRIVATE = <LiveRunVisibility.PRIVATE: 'private'>
PUBLIC = <LiveRunVisibility.PUBLIC: 'public'>
class LiveRunWithStream:
 26@_attrs_define
 27class LiveRunWithStream:
 28    """A run as `LiveRun` describes it, plus its `warmFrom` (absent only for a run started before the field existed) and
 29    its `streamUrl` when it has one. It is what **starting a run** and
 30    `GET /strategy/{strategyId}/live` return: your own run, read with your own credentials. Stopping a run
 31    returns `LiveRun`, which carries neither `warmFrom` nor the URL, and `GET /live/{runId}` returns `LiveRunDetail`,
 32    which carries `warmFrom` and never the URL.
 33
 34        Attributes:
 35            strategy_id (str): Unique identifier for a compiled strategy, derived from the source itself: the same code
 36                always yields the same id, for every caller. How much formatting the id ignores depends on
 37                the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 38                not.
 39                 Example: 6bsh31ikwkuivhtgcoa6s4.
 40            run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
 41                /live/public`.
 42            visibility (LiveRunVisibility):
 43            stage (LiveRunStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a second
 44                execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically when the
 45                24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts `LIVE`,
 46                unless you started it with `sandbox: true`.
 47            state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
 48                (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
 49                for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
 50                signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
 51                `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
 52                running run with something to look at. See the Live execution guide.
 53            desired (LiveRunDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
 54            sources (list[LiveSource]):
 55            params (LiveRunParams):
 56            params_version (int): Increments on every accepted `PUT .../params` call, including one that resends the current
 57                values.
 58            relay (bool): Whether this run's signals are relayed over the WebSocket channel described in the "Live
 59                execution" guide. It is the value requested at start, in either stage.
 60            started_at_ms (int): Epoch milliseconds.
 61            name (str | Unset):
 62            description (str | Unset):
 63            reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
 64                never a
 65                stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
 66                exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
 67                a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
 68                definition was refused, the run could not start after several attempts, the strategy failed while
 69                processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
 70                read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
 71                `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
 72                live-run limit) until then; one that can never run because its strategy cannot consume its source
 73                type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
 74            gate (LiveRunGate | Unset): The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and
 75                present once it ends, so an absent `gate` means the trial has not finished. A run that started in `LIVE` without
 76                a trial has it from the start: the verdict of the earlier run it relies on, with `inheritedFrom` naming that
 77                run. `passed` is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API:
 78                treat it as opaque.
 79            paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's `baseConfig`
 80                (same fields,
 81                defaults and limits), plus `output`. An empty object takes every default. Each quote
 82                currency the run trades gets its own simulated account, opened with `initialFunding` in
 83                that currency; accounts are never added together. As returned on a run, the block is
 84                normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
 85                in.
 86            stats (LiveRunStats | Unset): What a run has been doing, as of its last snapshot. The platform refreshes it
 87                about once a minute
 88                while the run is being executed, so `opsPerSecond` is an average over that interval, not an
 89                instantaneous rate.
 90            warm_from (int | Unset): The `warmFrom` in effect for this run, in seconds: the one requested when the run was
 91                started or, when none was, the one the platform chose (the distance from the run's start back to the start of
 92                the current 15-minute block, 0 to 900). It is never `null`. It is present on every run started since the field
 93                exists and absent from a run started before it existed. It never changes while the run exists.
 94            stream_url (str | Unset): The run's secret stream URL (`wss://…`). **Treat it like a password**: anyone who
 95                holds it can read
 96                this run's signals, from the sandbox stage on. Present only when the run was started with
 97                `stream: true`, is wanted running, has not had its stream revoked, and your plan still lets you
 98                broadcast; absent otherwise (a plan that lets you broadcast again gets the same URL back). Rotate
 99                it with `POST /live/{runId}/stream` if it leaks, revoke it with `DELETE /live/{runId}/stream`.
100    """
101
102    strategy_id: str
103    run_id: str
104    visibility: LiveRunVisibility
105    stage: LiveRunStage
106    state: str
107    desired: LiveRunDesired
108    sources: list[LiveSource]
109    params: LiveRunParams
110    params_version: int
111    relay: bool
112    started_at_ms: int
113    name: str | Unset = UNSET
114    description: str | Unset = UNSET
115    reason: str | Unset = UNSET
116    gate: LiveRunGate | Unset = UNSET
117    paper: LivePaperConfig | Unset = UNSET
118    stats: LiveRunStats | Unset = UNSET
119    warm_from: int | Unset = UNSET
120    stream_url: str | Unset = UNSET
121    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
122
123    def to_dict(self) -> dict[str, Any]:
124        strategy_id = self.strategy_id
125
126        run_id = self.run_id
127
128        visibility = self.visibility.value
129
130        stage = self.stage.value
131
132        state = self.state
133
134        desired = self.desired.value
135
136        sources = []
137        for sources_item_data in self.sources:
138            sources_item = sources_item_data.to_dict()
139            sources.append(sources_item)
140
141        params = self.params.to_dict()
142
143        params_version = self.params_version
144
145        relay = self.relay
146
147        started_at_ms = self.started_at_ms
148
149        name = self.name
150
151        description = self.description
152
153        reason = self.reason
154
155        gate: dict[str, Any] | Unset = UNSET
156        if not isinstance(self.gate, Unset):
157            gate = self.gate.to_dict()
158
159        paper: dict[str, Any] | Unset = UNSET
160        if not isinstance(self.paper, Unset):
161            paper = self.paper.to_dict()
162
163        stats: dict[str, Any] | Unset = UNSET
164        if not isinstance(self.stats, Unset):
165            stats = self.stats.to_dict()
166
167        warm_from = self.warm_from
168
169        stream_url = self.stream_url
170
171        field_dict: dict[str, Any] = {}
172        field_dict.update(self.additional_properties)
173        field_dict.update(
174            {
175                "strategyId": strategy_id,
176                "runId": run_id,
177                "visibility": visibility,
178                "stage": stage,
179                "state": state,
180                "desired": desired,
181                "sources": sources,
182                "params": params,
183                "paramsVersion": params_version,
184                "relay": relay,
185                "startedAtMs": started_at_ms,
186            }
187        )
188        if name is not UNSET:
189            field_dict["name"] = name
190        if description is not UNSET:
191            field_dict["description"] = description
192        if reason is not UNSET:
193            field_dict["reason"] = reason
194        if gate is not UNSET:
195            field_dict["gate"] = gate
196        if paper is not UNSET:
197            field_dict["paper"] = paper
198        if stats is not UNSET:
199            field_dict["stats"] = stats
200        if warm_from is not UNSET:
201            field_dict["warmFrom"] = warm_from
202        if stream_url is not UNSET:
203            field_dict["streamUrl"] = stream_url
204
205        return field_dict
206
207    @classmethod
208    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
209        from ..models.live_paper_config import LivePaperConfig
210        from ..models.live_run_gate import LiveRunGate
211        from ..models.live_run_params import LiveRunParams
212        from ..models.live_run_stats import LiveRunStats
213        from ..models.live_source import LiveSource
214
215        d = dict(src_dict)
216        strategy_id = d.pop("strategyId")
217
218        run_id = d.pop("runId")
219
220        visibility = LiveRunVisibility(d.pop("visibility"))
221
222        stage = LiveRunStage(d.pop("stage"))
223
224        state = d.pop("state")
225
226        desired = LiveRunDesired(d.pop("desired"))
227
228        sources = []
229        _sources = d.pop("sources")
230        for sources_item_data in _sources:
231            sources_item = LiveSource.from_dict(sources_item_data)
232
233            sources.append(sources_item)
234
235        params = LiveRunParams.from_dict(d.pop("params"))
236
237        params_version = d.pop("paramsVersion")
238
239        relay = d.pop("relay")
240
241        started_at_ms = d.pop("startedAtMs")
242
243        name = d.pop("name", UNSET)
244
245        description = d.pop("description", UNSET)
246
247        reason = d.pop("reason", UNSET)
248
249        _gate = d.pop("gate", UNSET)
250        gate: LiveRunGate | Unset
251        if isinstance(_gate, Unset):
252            gate = UNSET
253        else:
254            gate = LiveRunGate.from_dict(_gate)
255
256        _paper = d.pop("paper", UNSET)
257        paper: LivePaperConfig | Unset
258        if isinstance(_paper, Unset):
259            paper = UNSET
260        else:
261            paper = LivePaperConfig.from_dict(_paper)
262
263        _stats = d.pop("stats", UNSET)
264        stats: LiveRunStats | Unset
265        if isinstance(_stats, Unset):
266            stats = UNSET
267        else:
268            stats = LiveRunStats.from_dict(_stats)
269
270        warm_from = d.pop("warmFrom", UNSET)
271
272        stream_url = d.pop("streamUrl", UNSET)
273
274        live_run_with_stream = cls(
275            strategy_id=strategy_id,
276            run_id=run_id,
277            visibility=visibility,
278            stage=stage,
279            state=state,
280            desired=desired,
281            sources=sources,
282            params=params,
283            params_version=params_version,
284            relay=relay,
285            started_at_ms=started_at_ms,
286            name=name,
287            description=description,
288            reason=reason,
289            gate=gate,
290            paper=paper,
291            stats=stats,
292            warm_from=warm_from,
293            stream_url=stream_url,
294        )
295
296        live_run_with_stream.additional_properties = d
297        return live_run_with_stream
298
299    @property
300    def additional_keys(self) -> list[str]:
301        return list(self.additional_properties.keys())
302
303    def __getitem__(self, key: str) -> Any:
304        return self.additional_properties[key]
305
306    def __setitem__(self, key: str, value: Any) -> None:
307        self.additional_properties[key] = value
308
309    def __delitem__(self, key: str) -> None:
310        del self.additional_properties[key]
311
312    def __contains__(self, key: str) -> bool:
313        return key in self.additional_properties

A run as LiveRun describes it, plus its warmFrom (absent only for a run started before the field existed) and its streamUrl when it has one. It is what starting a run and GET /strategy/{strategyId}/live return: your own run, read with your own credentials. Stopping a run returns LiveRun, which carries neither warmFrom nor the URL, and GET /live/{runId} returns LiveRunDetail, which carries warmFrom and never the URL.

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. How much formatting the id ignores depends on
        the language — see `POST /strategy` for exactly which rewrites preserve it and which do
        not.
         Example: 6bsh31ikwkuivhtgcoa6s4.
    run_id (str): This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET
        /live/public`.
    visibility (LiveRunVisibility):
    stage (LiveRunStage): A new run starts `SANDBOX`, a 24-hour trial in which it is compared against a second
        execution and checked for resource use and stability. A run that passes moves to `LIVE` automatically when the
        24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts `LIVE`,
        unless you started it with `sandbox: true`.
    state (str): The run's health right now: `STARTING` (no runner has reported on it yet), `RUNNING`, `LAGGING`
        (behind the market data, usually while catching up; clears by itself), `HUNG` (stuck inside one strategy call
        for longer than allowed; clears when it returns), `DEGRADED` (its independent executions produced different
        signals), `FAILED` (refused, could not start or failed while running; `reason` says why) or `STOPPED`.
        `LAGGING`, `HUNG` and `DEGRADED` come and go on a running run. The set may grow: read an unknown value as a
        running run with something to look at. See the Live execution guide.
    desired (LiveRunDesired): What you last asked for. `state` can lag this briefly after `DELETE`.
    sources (list[LiveSource]):
    params (LiveRunParams):
    params_version (int): Increments on every accepted `PUT .../params` call, including one that resends the current
        values.
    relay (bool): Whether this run's signals are relayed over the WebSocket channel described in the "Live
        execution" guide. It is the value requested at start, in either stage.
    started_at_ms (int): Epoch milliseconds.
    name (str | Unset):
    description (str | Unset):
    reason (str | Unset): Why the run stopped or failed, when there is something to say; absent otherwise. It is
        never a
        stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
        exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
        a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
        definition was refused, the run could not start after several attempts, the strategy failed while
        processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
        read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
        `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
        live-run limit) until then; one that can never run because its strategy cannot consume its source
        type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
    gate (LiveRunGate | Unset): The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and
        present once it ends, so an absent `gate` means the trial has not finished. A run that started in `LIVE` without
        a trial has it from the start: the verdict of the earlier run it relies on, with `inheritedFrom` naming that
        run. `passed` is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API:
        treat it as opaque.
    paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's `baseConfig`
        (same fields,
        defaults and limits), plus `output`. An empty object takes every default. Each quote
        currency the run trades gets its own simulated account, opened with `initialFunding` in
        that currency; accounts are never added together. As returned on a run, the block is
        normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
        in.
    stats (LiveRunStats | Unset): What a run has been doing, as of its last snapshot. The platform refreshes it
        about once a minute
        while the run is being executed, so `opsPerSecond` is an average over that interval, not an
        instantaneous rate.
    warm_from (int | Unset): The `warmFrom` in effect for this run, in seconds: the one requested when the run was
        started or, when none was, the one the platform chose (the distance from the run's start back to the start of
        the current 15-minute block, 0 to 900). It is never `null`. It is present on every run started since the field
        exists and absent from a run started before it existed. It never changes while the run exists.
    stream_url (str | Unset): The run's secret stream URL (`wss://…`). **Treat it like a password**: anyone who
        holds it can read
        this run's signals, from the sandbox stage on. Present only when the run was started with
        `stream: true`, is wanted running, has not had its stream revoked, and your plan still lets you
        broadcast; absent otherwise (a plan that lets you broadcast again gets the same URL back). Rotate
        it with `POST /live/{runId}/stream` if it leaks, revoke it with `DELETE /live/{runId}/stream`.
LiveRunWithStream( strategy_id: str, run_id: str, visibility: LiveRunVisibility, stage: LiveRunStage, state: str, desired: LiveRunDesired, sources: list[LiveSource], params: LiveRunParams, params_version: int, relay: bool, started_at_ms: int, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, reason: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, gate: LiveRunGate | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, stats: LiveRunStats | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, warm_from: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, stream_url: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
42def __init__(self, strategy_id, run_id, visibility, stage, state, desired, sources, params, params_version, relay, started_at_ms, name=attr_dict['name'].default, description=attr_dict['description'].default, reason=attr_dict['reason'].default, gate=attr_dict['gate'].default, paper=attr_dict['paper'].default, stats=attr_dict['stats'].default, warm_from=attr_dict['warm_from'].default, stream_url=attr_dict['stream_url'].default):
43    self.strategy_id = strategy_id
44    self.run_id = run_id
45    self.visibility = visibility
46    self.stage = stage
47    self.state = state
48    self.desired = desired
49    self.sources = sources
50    self.params = params
51    self.params_version = params_version
52    self.relay = relay
53    self.started_at_ms = started_at_ms
54    self.name = name
55    self.description = description
56    self.reason = reason
57    self.gate = gate
58    self.paper = paper
59    self.stats = stats
60    self.warm_from = warm_from
61    self.stream_url = stream_url
62    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveRunWithStream.

strategy_id: str
run_id: str
visibility: LiveRunVisibility
stage: LiveRunStage
state: str
desired: LiveRunDesired
sources: list[LiveSource]
params: LiveRunParams
params_version: int
relay: bool
started_at_ms: int
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
reason: str | qtsurfer.api.client._generated.types.Unset
gate: LiveRunGate | qtsurfer.api.client._generated.types.Unset
paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset
stats: LiveRunStats | qtsurfer.api.client._generated.types.Unset
warm_from: int | qtsurfer.api.client._generated.types.Unset
stream_url: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
123    def to_dict(self) -> dict[str, Any]:
124        strategy_id = self.strategy_id
125
126        run_id = self.run_id
127
128        visibility = self.visibility.value
129
130        stage = self.stage.value
131
132        state = self.state
133
134        desired = self.desired.value
135
136        sources = []
137        for sources_item_data in self.sources:
138            sources_item = sources_item_data.to_dict()
139            sources.append(sources_item)
140
141        params = self.params.to_dict()
142
143        params_version = self.params_version
144
145        relay = self.relay
146
147        started_at_ms = self.started_at_ms
148
149        name = self.name
150
151        description = self.description
152
153        reason = self.reason
154
155        gate: dict[str, Any] | Unset = UNSET
156        if not isinstance(self.gate, Unset):
157            gate = self.gate.to_dict()
158
159        paper: dict[str, Any] | Unset = UNSET
160        if not isinstance(self.paper, Unset):
161            paper = self.paper.to_dict()
162
163        stats: dict[str, Any] | Unset = UNSET
164        if not isinstance(self.stats, Unset):
165            stats = self.stats.to_dict()
166
167        warm_from = self.warm_from
168
169        stream_url = self.stream_url
170
171        field_dict: dict[str, Any] = {}
172        field_dict.update(self.additional_properties)
173        field_dict.update(
174            {
175                "strategyId": strategy_id,
176                "runId": run_id,
177                "visibility": visibility,
178                "stage": stage,
179                "state": state,
180                "desired": desired,
181                "sources": sources,
182                "params": params,
183                "paramsVersion": params_version,
184                "relay": relay,
185                "startedAtMs": started_at_ms,
186            }
187        )
188        if name is not UNSET:
189            field_dict["name"] = name
190        if description is not UNSET:
191            field_dict["description"] = description
192        if reason is not UNSET:
193            field_dict["reason"] = reason
194        if gate is not UNSET:
195            field_dict["gate"] = gate
196        if paper is not UNSET:
197            field_dict["paper"] = paper
198        if stats is not UNSET:
199            field_dict["stats"] = stats
200        if warm_from is not UNSET:
201            field_dict["warmFrom"] = warm_from
202        if stream_url is not UNSET:
203            field_dict["streamUrl"] = stream_url
204
205        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
207    @classmethod
208    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
209        from ..models.live_paper_config import LivePaperConfig
210        from ..models.live_run_gate import LiveRunGate
211        from ..models.live_run_params import LiveRunParams
212        from ..models.live_run_stats import LiveRunStats
213        from ..models.live_source import LiveSource
214
215        d = dict(src_dict)
216        strategy_id = d.pop("strategyId")
217
218        run_id = d.pop("runId")
219
220        visibility = LiveRunVisibility(d.pop("visibility"))
221
222        stage = LiveRunStage(d.pop("stage"))
223
224        state = d.pop("state")
225
226        desired = LiveRunDesired(d.pop("desired"))
227
228        sources = []
229        _sources = d.pop("sources")
230        for sources_item_data in _sources:
231            sources_item = LiveSource.from_dict(sources_item_data)
232
233            sources.append(sources_item)
234
235        params = LiveRunParams.from_dict(d.pop("params"))
236
237        params_version = d.pop("paramsVersion")
238
239        relay = d.pop("relay")
240
241        started_at_ms = d.pop("startedAtMs")
242
243        name = d.pop("name", UNSET)
244
245        description = d.pop("description", UNSET)
246
247        reason = d.pop("reason", UNSET)
248
249        _gate = d.pop("gate", UNSET)
250        gate: LiveRunGate | Unset
251        if isinstance(_gate, Unset):
252            gate = UNSET
253        else:
254            gate = LiveRunGate.from_dict(_gate)
255
256        _paper = d.pop("paper", UNSET)
257        paper: LivePaperConfig | Unset
258        if isinstance(_paper, Unset):
259            paper = UNSET
260        else:
261            paper = LivePaperConfig.from_dict(_paper)
262
263        _stats = d.pop("stats", UNSET)
264        stats: LiveRunStats | Unset
265        if isinstance(_stats, Unset):
266            stats = UNSET
267        else:
268            stats = LiveRunStats.from_dict(_stats)
269
270        warm_from = d.pop("warmFrom", UNSET)
271
272        stream_url = d.pop("streamUrl", UNSET)
273
274        live_run_with_stream = cls(
275            strategy_id=strategy_id,
276            run_id=run_id,
277            visibility=visibility,
278            stage=stage,
279            state=state,
280            desired=desired,
281            sources=sources,
282            params=params,
283            params_version=params_version,
284            relay=relay,
285            started_at_ms=started_at_ms,
286            name=name,
287            description=description,
288            reason=reason,
289            gate=gate,
290            paper=paper,
291            stats=stats,
292            warm_from=warm_from,
293            stream_url=stream_url,
294        )
295
296        live_run_with_stream.additional_properties = d
297        return live_run_with_stream
additional_keys: list[str]
299    @property
300    def additional_keys(self) -> list[str]:
301        return list(self.additional_properties.keys())
class LiveSignal:
 23@_attrs_define
 24class LiveSignal:
 25    """One signal, in the same shape the real-time signal channel delivers.
 26
 27    Attributes:
 28        v (int): Envelope schema version.
 29        signal_id (str): Stable id for this exact signal — dedupe on it across reconnects or overlapping reads.
 30        run_id (str):
 31        stage (LiveSignalStage): The stage the run was in when this signal was produced.
 32        type_ (LiveSignalType): `paper` items appear only for a run whose `paper.output` is `mix`; they are not relayed
 33            over the WebSocket channel.
 34        event_ts_ms (int): Market time the signal was produced.
 35        emitted_at_ms (int): Time it was published — always at or after `eventTsMs`.
 36        instrument (LiveSignalInstrument | None): The instrument the signal is about. `null` only for a `paper` item
 37            about a whole account (`equity`, `mark`, `kpi`), whose `data.currency` names the account.
 38        digest (str): Content hash, for checking that two independent deliveries of the same signal agree.
 39        params_version (int | Unset): The parameter set in force when this signal was produced.
 40        kind (None | str | Unset): `BUY`/`SELL` for a `hint`, the command name for a `command`; for `paper`, what the
 41            item is: `fill`, `trade`, `equity`, `mark`, `kpi` or `gap`. Absent otherwise.
 42        order (LiveSignalOrderType0 | None | Unset): Present only for a `hint`.
 43        data (LiveSignalData | Unset): The signal's own free-form payload, what the strategy put there with
 44            `signal.set(...)`. Whoever may read the run may read it, so on a `public` run it is public. A signal whose
 45            `data` is over 8 KiB (8,192 bytes of its JSON) is not pushed on the WebSocket channel, and `GET
 46            /live/{runId}/signals` returns it whole.
 47        regenerated (bool | Unset): `true` only for a signal republished to fill a gap in the record.
 48    """
 49
 50    v: int
 51    signal_id: str
 52    run_id: str
 53    stage: LiveSignalStage
 54    type_: LiveSignalType
 55    event_ts_ms: int
 56    emitted_at_ms: int
 57    instrument: LiveSignalInstrument | None
 58    digest: str
 59    params_version: int | Unset = UNSET
 60    kind: None | str | Unset = UNSET
 61    order: LiveSignalOrderType0 | None | Unset = UNSET
 62    data: LiveSignalData | Unset = UNSET
 63    regenerated: bool | Unset = UNSET
 64    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 65
 66    def to_dict(self) -> dict[str, Any]:
 67        from ..models.live_signal_instrument import LiveSignalInstrument
 68        from ..models.live_signal_order_type_0 import LiveSignalOrderType0
 69
 70        v = self.v
 71
 72        signal_id = self.signal_id
 73
 74        run_id = self.run_id
 75
 76        stage = self.stage.value
 77
 78        type_ = self.type_.value
 79
 80        event_ts_ms = self.event_ts_ms
 81
 82        emitted_at_ms = self.emitted_at_ms
 83
 84        instrument: dict[str, Any] | None
 85        if isinstance(self.instrument, LiveSignalInstrument):
 86            instrument = self.instrument.to_dict()
 87        else:
 88            instrument = self.instrument
 89
 90        digest = self.digest
 91
 92        params_version = self.params_version
 93
 94        kind: None | str | Unset
 95        if isinstance(self.kind, Unset):
 96            kind = UNSET
 97        else:
 98            kind = self.kind
 99
100        order: dict[str, Any] | None | Unset
101        if isinstance(self.order, Unset):
102            order = UNSET
103        elif isinstance(self.order, LiveSignalOrderType0):
104            order = self.order.to_dict()
105        else:
106            order = self.order
107
108        data: dict[str, Any] | Unset = UNSET
109        if not isinstance(self.data, Unset):
110            data = self.data.to_dict()
111
112        regenerated = self.regenerated
113
114        field_dict: dict[str, Any] = {}
115        field_dict.update(self.additional_properties)
116        field_dict.update(
117            {
118                "v": v,
119                "signalId": signal_id,
120                "runId": run_id,
121                "stage": stage,
122                "type": type_,
123                "eventTsMs": event_ts_ms,
124                "emittedAtMs": emitted_at_ms,
125                "instrument": instrument,
126                "digest": digest,
127            }
128        )
129        if params_version is not UNSET:
130            field_dict["paramsVersion"] = params_version
131        if kind is not UNSET:
132            field_dict["kind"] = kind
133        if order is not UNSET:
134            field_dict["order"] = order
135        if data is not UNSET:
136            field_dict["data"] = data
137        if regenerated is not UNSET:
138            field_dict["regenerated"] = regenerated
139
140        return field_dict
141
142    @classmethod
143    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
144        from ..models.live_signal_data import LiveSignalData
145        from ..models.live_signal_instrument import LiveSignalInstrument
146        from ..models.live_signal_order_type_0 import LiveSignalOrderType0
147
148        d = dict(src_dict)
149        v = d.pop("v")
150
151        signal_id = d.pop("signalId")
152
153        run_id = d.pop("runId")
154
155        stage = LiveSignalStage(d.pop("stage"))
156
157        type_ = LiveSignalType(d.pop("type"))
158
159        event_ts_ms = d.pop("eventTsMs")
160
161        emitted_at_ms = d.pop("emittedAtMs")
162
163        def _parse_instrument(data: object) -> LiveSignalInstrument | None:
164            if data is None:
165                return data
166            try:
167                if not isinstance(data, dict):
168                    raise TypeError()
169                instrument_type_0 = LiveSignalInstrument.from_dict(data)
170
171                return instrument_type_0
172            except (TypeError, ValueError, AttributeError, KeyError):
173                pass
174            return cast(LiveSignalInstrument | None, data)
175
176        instrument = _parse_instrument(d.pop("instrument"))
177
178        digest = d.pop("digest")
179
180        params_version = d.pop("paramsVersion", UNSET)
181
182        def _parse_kind(data: object) -> None | str | Unset:
183            if data is None:
184                return data
185            if isinstance(data, Unset):
186                return data
187            return cast(None | str | Unset, data)
188
189        kind = _parse_kind(d.pop("kind", UNSET))
190
191        def _parse_order(data: object) -> LiveSignalOrderType0 | None | Unset:
192            if data is None:
193                return data
194            if isinstance(data, Unset):
195                return data
196            try:
197                if not isinstance(data, dict):
198                    raise TypeError()
199                componentsschemas_live_signal_order_type_0 = LiveSignalOrderType0.from_dict(data)
200
201                return componentsschemas_live_signal_order_type_0
202            except (TypeError, ValueError, AttributeError, KeyError):
203                pass
204            return cast(LiveSignalOrderType0 | None | Unset, data)
205
206        order = _parse_order(d.pop("order", UNSET))
207
208        _data = d.pop("data", UNSET)
209        data: LiveSignalData | Unset
210        if isinstance(_data, Unset):
211            data = UNSET
212        else:
213            data = LiveSignalData.from_dict(_data)
214
215        regenerated = d.pop("regenerated", UNSET)
216
217        live_signal = cls(
218            v=v,
219            signal_id=signal_id,
220            run_id=run_id,
221            stage=stage,
222            type_=type_,
223            event_ts_ms=event_ts_ms,
224            emitted_at_ms=emitted_at_ms,
225            instrument=instrument,
226            digest=digest,
227            params_version=params_version,
228            kind=kind,
229            order=order,
230            data=data,
231            regenerated=regenerated,
232        )
233
234        live_signal.additional_properties = d
235        return live_signal
236
237    @property
238    def additional_keys(self) -> list[str]:
239        return list(self.additional_properties.keys())
240
241    def __getitem__(self, key: str) -> Any:
242        return self.additional_properties[key]
243
244    def __setitem__(self, key: str, value: Any) -> None:
245        self.additional_properties[key] = value
246
247    def __delitem__(self, key: str) -> None:
248        del self.additional_properties[key]
249
250    def __contains__(self, key: str) -> bool:
251        return key in self.additional_properties

One signal, in the same shape the real-time signal channel delivers.

Attributes: v (int): Envelope schema version. signal_id (str): Stable id for this exact signal — dedupe on it across reconnects or overlapping reads. run_id (str): stage (LiveSignalStage): The stage the run was in when this signal was produced. type_ (LiveSignalType): paper items appear only for a run whose paper.output is mix; they are not relayed over the WebSocket channel. event_ts_ms (int): Market time the signal was produced. emitted_at_ms (int): Time it was published — always at or after eventTsMs. instrument (LiveSignalInstrument | None): The instrument the signal is about. null only for a paper item about a whole account (equity, mark, kpi), whose data.currency names the account. digest (str): Content hash, for checking that two independent deliveries of the same signal agree. params_version (int | Unset): The parameter set in force when this signal was produced. kind (None | str | Unset): BUY/SELL for a hint, the command name for a command; for paper, what the item is: fill, trade, equity, mark, kpi or gap. Absent otherwise. order (LiveSignalOrderType0 | None | Unset): Present only for a hint. data (LiveSignalData | Unset): The signal's own free-form payload, what the strategy put there with signal.set(...). Whoever may read the run may read it, so on a public run it is public. A signal whose data is over 8 KiB (8,192 bytes of its JSON) is not pushed on the WebSocket channel, and GET /live/{runId}/signals returns it whole. regenerated (bool | Unset): true only for a signal republished to fill a gap in the record.

LiveSignal( v: int, signal_id: str, run_id: str, stage: LiveSignalStage, type_: LiveSignalType, event_ts_ms: int, emitted_at_ms: int, instrument: LiveSignalInstrument | None, digest: str, params_version: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, kind: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, order: LiveSignalOrderType0 | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, data: LiveSignalData | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, regenerated: bool | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
37def __init__(self, v, signal_id, run_id, stage, type_, event_ts_ms, emitted_at_ms, instrument, digest, params_version=attr_dict['params_version'].default, kind=attr_dict['kind'].default, order=attr_dict['order'].default, data=attr_dict['data'].default, regenerated=attr_dict['regenerated'].default):
38    self.v = v
39    self.signal_id = signal_id
40    self.run_id = run_id
41    self.stage = stage
42    self.type_ = type_
43    self.event_ts_ms = event_ts_ms
44    self.emitted_at_ms = emitted_at_ms
45    self.instrument = instrument
46    self.digest = digest
47    self.params_version = params_version
48    self.kind = kind
49    self.order = order
50    self.data = data
51    self.regenerated = regenerated
52    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSignal.

v: int
signal_id: str
run_id: str
event_ts_ms: int
emitted_at_ms: int
instrument: LiveSignalInstrument | None
digest: str
params_version: int | qtsurfer.api.client._generated.types.Unset
kind: None | str | qtsurfer.api.client._generated.types.Unset
order: LiveSignalOrderType0 | None | qtsurfer.api.client._generated.types.Unset
data: LiveSignalData | qtsurfer.api.client._generated.types.Unset
regenerated: bool | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 66    def to_dict(self) -> dict[str, Any]:
 67        from ..models.live_signal_instrument import LiveSignalInstrument
 68        from ..models.live_signal_order_type_0 import LiveSignalOrderType0
 69
 70        v = self.v
 71
 72        signal_id = self.signal_id
 73
 74        run_id = self.run_id
 75
 76        stage = self.stage.value
 77
 78        type_ = self.type_.value
 79
 80        event_ts_ms = self.event_ts_ms
 81
 82        emitted_at_ms = self.emitted_at_ms
 83
 84        instrument: dict[str, Any] | None
 85        if isinstance(self.instrument, LiveSignalInstrument):
 86            instrument = self.instrument.to_dict()
 87        else:
 88            instrument = self.instrument
 89
 90        digest = self.digest
 91
 92        params_version = self.params_version
 93
 94        kind: None | str | Unset
 95        if isinstance(self.kind, Unset):
 96            kind = UNSET
 97        else:
 98            kind = self.kind
 99
100        order: dict[str, Any] | None | Unset
101        if isinstance(self.order, Unset):
102            order = UNSET
103        elif isinstance(self.order, LiveSignalOrderType0):
104            order = self.order.to_dict()
105        else:
106            order = self.order
107
108        data: dict[str, Any] | Unset = UNSET
109        if not isinstance(self.data, Unset):
110            data = self.data.to_dict()
111
112        regenerated = self.regenerated
113
114        field_dict: dict[str, Any] = {}
115        field_dict.update(self.additional_properties)
116        field_dict.update(
117            {
118                "v": v,
119                "signalId": signal_id,
120                "runId": run_id,
121                "stage": stage,
122                "type": type_,
123                "eventTsMs": event_ts_ms,
124                "emittedAtMs": emitted_at_ms,
125                "instrument": instrument,
126                "digest": digest,
127            }
128        )
129        if params_version is not UNSET:
130            field_dict["paramsVersion"] = params_version
131        if kind is not UNSET:
132            field_dict["kind"] = kind
133        if order is not UNSET:
134            field_dict["order"] = order
135        if data is not UNSET:
136            field_dict["data"] = data
137        if regenerated is not UNSET:
138            field_dict["regenerated"] = regenerated
139
140        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
142    @classmethod
143    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
144        from ..models.live_signal_data import LiveSignalData
145        from ..models.live_signal_instrument import LiveSignalInstrument
146        from ..models.live_signal_order_type_0 import LiveSignalOrderType0
147
148        d = dict(src_dict)
149        v = d.pop("v")
150
151        signal_id = d.pop("signalId")
152
153        run_id = d.pop("runId")
154
155        stage = LiveSignalStage(d.pop("stage"))
156
157        type_ = LiveSignalType(d.pop("type"))
158
159        event_ts_ms = d.pop("eventTsMs")
160
161        emitted_at_ms = d.pop("emittedAtMs")
162
163        def _parse_instrument(data: object) -> LiveSignalInstrument | None:
164            if data is None:
165                return data
166            try:
167                if not isinstance(data, dict):
168                    raise TypeError()
169                instrument_type_0 = LiveSignalInstrument.from_dict(data)
170
171                return instrument_type_0
172            except (TypeError, ValueError, AttributeError, KeyError):
173                pass
174            return cast(LiveSignalInstrument | None, data)
175
176        instrument = _parse_instrument(d.pop("instrument"))
177
178        digest = d.pop("digest")
179
180        params_version = d.pop("paramsVersion", UNSET)
181
182        def _parse_kind(data: object) -> None | str | Unset:
183            if data is None:
184                return data
185            if isinstance(data, Unset):
186                return data
187            return cast(None | str | Unset, data)
188
189        kind = _parse_kind(d.pop("kind", UNSET))
190
191        def _parse_order(data: object) -> LiveSignalOrderType0 | None | Unset:
192            if data is None:
193                return data
194            if isinstance(data, Unset):
195                return data
196            try:
197                if not isinstance(data, dict):
198                    raise TypeError()
199                componentsschemas_live_signal_order_type_0 = LiveSignalOrderType0.from_dict(data)
200
201                return componentsschemas_live_signal_order_type_0
202            except (TypeError, ValueError, AttributeError, KeyError):
203                pass
204            return cast(LiveSignalOrderType0 | None | Unset, data)
205
206        order = _parse_order(d.pop("order", UNSET))
207
208        _data = d.pop("data", UNSET)
209        data: LiveSignalData | Unset
210        if isinstance(_data, Unset):
211            data = UNSET
212        else:
213            data = LiveSignalData.from_dict(_data)
214
215        regenerated = d.pop("regenerated", UNSET)
216
217        live_signal = cls(
218            v=v,
219            signal_id=signal_id,
220            run_id=run_id,
221            stage=stage,
222            type_=type_,
223            event_ts_ms=event_ts_ms,
224            emitted_at_ms=emitted_at_ms,
225            instrument=instrument,
226            digest=digest,
227            params_version=params_version,
228            kind=kind,
229            order=order,
230            data=data,
231            regenerated=regenerated,
232        )
233
234        live_signal.additional_properties = d
235        return live_signal
additional_keys: list[str]
237    @property
238    def additional_keys(self) -> list[str]:
239        return list(self.additional_properties.keys())
class LiveSignalData:
13@_attrs_define
14class LiveSignalData:
15    """The signal's own free-form payload, what the strategy put there with `signal.set(...)`. Whoever may read the run may
16    read it, so on a `public` run it is public. A signal whose `data` is over 8 KiB (8,192 bytes of its JSON) is not
17    pushed on the WebSocket channel, and `GET /live/{runId}/signals` returns it whole.
18
19    """
20
21    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
22
23    def to_dict(self) -> dict[str, Any]:
24
25        field_dict: dict[str, Any] = {}
26        field_dict.update(self.additional_properties)
27
28        return field_dict
29
30    @classmethod
31    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
32        d = dict(src_dict)
33        live_signal_data = cls()
34
35        live_signal_data.additional_properties = d
36        return live_signal_data
37
38    @property
39    def additional_keys(self) -> list[str]:
40        return list(self.additional_properties.keys())
41
42    def __getitem__(self, key: str) -> Any:
43        return self.additional_properties[key]
44
45    def __setitem__(self, key: str, value: Any) -> None:
46        self.additional_properties[key] = value
47
48    def __delitem__(self, key: str) -> None:
49        del self.additional_properties[key]
50
51    def __contains__(self, key: str) -> bool:
52        return key in self.additional_properties

The signal's own free-form payload, what the strategy put there with signal.set(...). Whoever may read the run may read it, so on a public run it is public. A signal whose data is over 8 KiB (8,192 bytes of its JSON) is not pushed on the WebSocket channel, and GET /live/{runId}/signals returns it whole.

LiveSignalData()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSignalData.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
23    def to_dict(self) -> dict[str, Any]:
24
25        field_dict: dict[str, Any] = {}
26        field_dict.update(self.additional_properties)
27
28        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
30    @classmethod
31    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
32        d = dict(src_dict)
33        live_signal_data = cls()
34
35        live_signal_data.additional_properties = d
36        return live_signal_data
additional_keys: list[str]
38    @property
39    def additional_keys(self) -> list[str]:
40        return list(self.additional_properties.keys())
class LiveSignalInstrument:
15@_attrs_define
16class LiveSignalInstrument:
17    """
18    Attributes:
19        exchange (str | Unset):
20        segment (str | Unset):
21        symbol (str | Unset): Slashed form, e.g. `BTC/USDT`.
22    """
23
24    exchange: str | Unset = UNSET
25    segment: str | Unset = UNSET
26    symbol: str | Unset = UNSET
27    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
29    def to_dict(self) -> dict[str, Any]:
30        exchange = self.exchange
31
32        segment = self.segment
33
34        symbol = self.symbol
35
36        field_dict: dict[str, Any] = {}
37        field_dict.update(self.additional_properties)
38        field_dict.update({})
39        if exchange is not UNSET:
40            field_dict["exchange"] = exchange
41        if segment is not UNSET:
42            field_dict["segment"] = segment
43        if symbol is not UNSET:
44            field_dict["symbol"] = symbol
45
46        return field_dict
47
48    @classmethod
49    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
50        d = dict(src_dict)
51        exchange = d.pop("exchange", UNSET)
52
53        segment = d.pop("segment", UNSET)
54
55        symbol = d.pop("symbol", UNSET)
56
57        live_signal_instrument = cls(
58            exchange=exchange,
59            segment=segment,
60            symbol=symbol,
61        )
62
63        live_signal_instrument.additional_properties = d
64        return live_signal_instrument
65
66    @property
67    def additional_keys(self) -> list[str]:
68        return list(self.additional_properties.keys())
69
70    def __getitem__(self, key: str) -> Any:
71        return self.additional_properties[key]
72
73    def __setitem__(self, key: str, value: Any) -> None:
74        self.additional_properties[key] = value
75
76    def __delitem__(self, key: str) -> None:
77        del self.additional_properties[key]
78
79    def __contains__(self, key: str) -> bool:
80        return key in self.additional_properties

Attributes: exchange (str | Unset): segment (str | Unset): symbol (str | Unset): Slashed form, e.g. BTC/USDT.

LiveSignalInstrument( exchange: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, segment: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, symbol: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
26def __init__(self, exchange=attr_dict['exchange'].default, segment=attr_dict['segment'].default, symbol=attr_dict['symbol'].default):
27    self.exchange = exchange
28    self.segment = segment
29    self.symbol = symbol
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSignalInstrument.

exchange: str | qtsurfer.api.client._generated.types.Unset
segment: str | qtsurfer.api.client._generated.types.Unset
symbol: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
29    def to_dict(self) -> dict[str, Any]:
30        exchange = self.exchange
31
32        segment = self.segment
33
34        symbol = self.symbol
35
36        field_dict: dict[str, Any] = {}
37        field_dict.update(self.additional_properties)
38        field_dict.update({})
39        if exchange is not UNSET:
40            field_dict["exchange"] = exchange
41        if segment is not UNSET:
42            field_dict["segment"] = segment
43        if symbol is not UNSET:
44            field_dict["symbol"] = symbol
45
46        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
48    @classmethod
49    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
50        d = dict(src_dict)
51        exchange = d.pop("exchange", UNSET)
52
53        segment = d.pop("segment", UNSET)
54
55        symbol = d.pop("symbol", UNSET)
56
57        live_signal_instrument = cls(
58            exchange=exchange,
59            segment=segment,
60            symbol=symbol,
61        )
62
63        live_signal_instrument.additional_properties = d
64        return live_signal_instrument
additional_keys: list[str]
66    @property
67    def additional_keys(self) -> list[str]:
68        return list(self.additional_properties.keys())
class LiveSignalOrderType0:
 15@_attrs_define
 16class LiveSignalOrderType0:
 17    """Present only for a `hint`.
 18
 19    Attributes:
 20        order_kind (str | Unset):
 21        price (None | str | Unset):
 22        amount (None | str | Unset):
 23        stop_price (None | str | Unset):
 24        trail_pct (None | str | Unset):
 25    """
 26
 27    order_kind: str | Unset = UNSET
 28    price: None | str | Unset = UNSET
 29    amount: None | str | Unset = UNSET
 30    stop_price: None | str | Unset = UNSET
 31    trail_pct: None | str | Unset = UNSET
 32    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 33
 34    def to_dict(self) -> dict[str, Any]:
 35        order_kind = self.order_kind
 36
 37        price: None | str | Unset
 38        if isinstance(self.price, Unset):
 39            price = UNSET
 40        else:
 41            price = self.price
 42
 43        amount: None | str | Unset
 44        if isinstance(self.amount, Unset):
 45            amount = UNSET
 46        else:
 47            amount = self.amount
 48
 49        stop_price: None | str | Unset
 50        if isinstance(self.stop_price, Unset):
 51            stop_price = UNSET
 52        else:
 53            stop_price = self.stop_price
 54
 55        trail_pct: None | str | Unset
 56        if isinstance(self.trail_pct, Unset):
 57            trail_pct = UNSET
 58        else:
 59            trail_pct = self.trail_pct
 60
 61        field_dict: dict[str, Any] = {}
 62        field_dict.update(self.additional_properties)
 63        field_dict.update({})
 64        if order_kind is not UNSET:
 65            field_dict["orderKind"] = order_kind
 66        if price is not UNSET:
 67            field_dict["price"] = price
 68        if amount is not UNSET:
 69            field_dict["amount"] = amount
 70        if stop_price is not UNSET:
 71            field_dict["stopPrice"] = stop_price
 72        if trail_pct is not UNSET:
 73            field_dict["trailPct"] = trail_pct
 74
 75        return field_dict
 76
 77    @classmethod
 78    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 79        d = dict(src_dict)
 80        order_kind = d.pop("orderKind", UNSET)
 81
 82        def _parse_price(data: object) -> None | str | Unset:
 83            if data is None:
 84                return data
 85            if isinstance(data, Unset):
 86                return data
 87            return cast(None | str | Unset, data)
 88
 89        price = _parse_price(d.pop("price", UNSET))
 90
 91        def _parse_amount(data: object) -> None | str | Unset:
 92            if data is None:
 93                return data
 94            if isinstance(data, Unset):
 95                return data
 96            return cast(None | str | Unset, data)
 97
 98        amount = _parse_amount(d.pop("amount", UNSET))
 99
100        def _parse_stop_price(data: object) -> None | str | Unset:
101            if data is None:
102                return data
103            if isinstance(data, Unset):
104                return data
105            return cast(None | str | Unset, data)
106
107        stop_price = _parse_stop_price(d.pop("stopPrice", UNSET))
108
109        def _parse_trail_pct(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        trail_pct = _parse_trail_pct(d.pop("trailPct", UNSET))
117
118        live_signal_order_type_0 = cls(
119            order_kind=order_kind,
120            price=price,
121            amount=amount,
122            stop_price=stop_price,
123            trail_pct=trail_pct,
124        )
125
126        live_signal_order_type_0.additional_properties = d
127        return live_signal_order_type_0
128
129    @property
130    def additional_keys(self) -> list[str]:
131        return list(self.additional_properties.keys())
132
133    def __getitem__(self, key: str) -> Any:
134        return self.additional_properties[key]
135
136    def __setitem__(self, key: str, value: Any) -> None:
137        self.additional_properties[key] = value
138
139    def __delitem__(self, key: str) -> None:
140        del self.additional_properties[key]
141
142    def __contains__(self, key: str) -> bool:
143        return key in self.additional_properties

Present only for a hint.

Attributes: order_kind (str | Unset): price (None | str | Unset): amount (None | str | Unset): stop_price (None | str | Unset): trail_pct (None | str | Unset):

LiveSignalOrderType0( order_kind: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, price: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, amount: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, stop_price: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, trail_pct: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
28def __init__(self, order_kind=attr_dict['order_kind'].default, price=attr_dict['price'].default, amount=attr_dict['amount'].default, stop_price=attr_dict['stop_price'].default, trail_pct=attr_dict['trail_pct'].default):
29    self.order_kind = order_kind
30    self.price = price
31    self.amount = amount
32    self.stop_price = stop_price
33    self.trail_pct = trail_pct
34    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSignalOrderType0.

order_kind: str | qtsurfer.api.client._generated.types.Unset
price: None | str | qtsurfer.api.client._generated.types.Unset
amount: None | str | qtsurfer.api.client._generated.types.Unset
stop_price: None | str | qtsurfer.api.client._generated.types.Unset
trail_pct: None | str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
34    def to_dict(self) -> dict[str, Any]:
35        order_kind = self.order_kind
36
37        price: None | str | Unset
38        if isinstance(self.price, Unset):
39            price = UNSET
40        else:
41            price = self.price
42
43        amount: None | str | Unset
44        if isinstance(self.amount, Unset):
45            amount = UNSET
46        else:
47            amount = self.amount
48
49        stop_price: None | str | Unset
50        if isinstance(self.stop_price, Unset):
51            stop_price = UNSET
52        else:
53            stop_price = self.stop_price
54
55        trail_pct: None | str | Unset
56        if isinstance(self.trail_pct, Unset):
57            trail_pct = UNSET
58        else:
59            trail_pct = self.trail_pct
60
61        field_dict: dict[str, Any] = {}
62        field_dict.update(self.additional_properties)
63        field_dict.update({})
64        if order_kind is not UNSET:
65            field_dict["orderKind"] = order_kind
66        if price is not UNSET:
67            field_dict["price"] = price
68        if amount is not UNSET:
69            field_dict["amount"] = amount
70        if stop_price is not UNSET:
71            field_dict["stopPrice"] = stop_price
72        if trail_pct is not UNSET:
73            field_dict["trailPct"] = trail_pct
74
75        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 77    @classmethod
 78    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 79        d = dict(src_dict)
 80        order_kind = d.pop("orderKind", UNSET)
 81
 82        def _parse_price(data: object) -> None | str | Unset:
 83            if data is None:
 84                return data
 85            if isinstance(data, Unset):
 86                return data
 87            return cast(None | str | Unset, data)
 88
 89        price = _parse_price(d.pop("price", UNSET))
 90
 91        def _parse_amount(data: object) -> None | str | Unset:
 92            if data is None:
 93                return data
 94            if isinstance(data, Unset):
 95                return data
 96            return cast(None | str | Unset, data)
 97
 98        amount = _parse_amount(d.pop("amount", UNSET))
 99
100        def _parse_stop_price(data: object) -> None | str | Unset:
101            if data is None:
102                return data
103            if isinstance(data, Unset):
104                return data
105            return cast(None | str | Unset, data)
106
107        stop_price = _parse_stop_price(d.pop("stopPrice", UNSET))
108
109        def _parse_trail_pct(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        trail_pct = _parse_trail_pct(d.pop("trailPct", UNSET))
117
118        live_signal_order_type_0 = cls(
119            order_kind=order_kind,
120            price=price,
121            amount=amount,
122            stop_price=stop_price,
123            trail_pct=trail_pct,
124        )
125
126        live_signal_order_type_0.additional_properties = d
127        return live_signal_order_type_0
additional_keys: list[str]
129    @property
130    def additional_keys(self) -> list[str]:
131        return list(self.additional_properties.keys())
class LiveSignalPage:
 20@_attrs_define
 21class LiveSignalPage:
 22    """One page of a run's recorded signals, oldest first.
 23
 24    Attributes:
 25        signals (list[LiveSignal]):
 26        available_since_ms (int | Unset): The oldest moment this run's signals can still be read from. Absent when the
 27            run has produced nothing yet. It moves forward over time as older signals are discarded, so a `sinceMs` earlier
 28            than this is served from here instead.
 29        field_links (PublicLiveListLinks | Unset): Present only when another page exists.
 30    """
 31
 32    signals: list[LiveSignal]
 33    available_since_ms: int | Unset = UNSET
 34    field_links: PublicLiveListLinks | Unset = UNSET
 35    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 36
 37    def to_dict(self) -> dict[str, Any]:
 38        signals = []
 39        for signals_item_data in self.signals:
 40            signals_item = signals_item_data.to_dict()
 41            signals.append(signals_item)
 42
 43        available_since_ms = self.available_since_ms
 44
 45        field_links: dict[str, Any] | Unset = UNSET
 46        if not isinstance(self.field_links, Unset):
 47            field_links = self.field_links.to_dict()
 48
 49        field_dict: dict[str, Any] = {}
 50        field_dict.update(self.additional_properties)
 51        field_dict.update(
 52            {
 53                "signals": signals,
 54            }
 55        )
 56        if available_since_ms is not UNSET:
 57            field_dict["availableSinceMs"] = available_since_ms
 58        if field_links is not UNSET:
 59            field_dict["_links"] = field_links
 60
 61        return field_dict
 62
 63    @classmethod
 64    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 65        from ..models.live_signal import LiveSignal
 66        from ..models.public_live_list_links import PublicLiveListLinks
 67
 68        d = dict(src_dict)
 69        signals = []
 70        _signals = d.pop("signals")
 71        for signals_item_data in _signals:
 72            signals_item = LiveSignal.from_dict(signals_item_data)
 73
 74            signals.append(signals_item)
 75
 76        available_since_ms = d.pop("availableSinceMs", UNSET)
 77
 78        _field_links = d.pop("_links", UNSET)
 79        field_links: PublicLiveListLinks | Unset
 80        if isinstance(_field_links, Unset):
 81            field_links = UNSET
 82        else:
 83            field_links = PublicLiveListLinks.from_dict(_field_links)
 84
 85        live_signal_page = cls(
 86            signals=signals,
 87            available_since_ms=available_since_ms,
 88            field_links=field_links,
 89        )
 90
 91        live_signal_page.additional_properties = d
 92        return live_signal_page
 93
 94    @property
 95    def additional_keys(self) -> list[str]:
 96        return list(self.additional_properties.keys())
 97
 98    def __getitem__(self, key: str) -> Any:
 99        return self.additional_properties[key]
100
101    def __setitem__(self, key: str, value: Any) -> None:
102        self.additional_properties[key] = value
103
104    def __delitem__(self, key: str) -> None:
105        del self.additional_properties[key]
106
107    def __contains__(self, key: str) -> bool:
108        return key in self.additional_properties

One page of a run's recorded signals, oldest first.

Attributes: signals (list[LiveSignal]): available_since_ms (int | Unset): The oldest moment this run's signals can still be read from. Absent when the run has produced nothing yet. It moves forward over time as older signals are discarded, so a sinceMs earlier than this is served from here instead. field_links (PublicLiveListLinks | Unset): Present only when another page exists.

LiveSignalPage( signals: list[LiveSignal], available_since_ms: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, field_links: PublicLiveListLinks | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
26def __init__(self, signals, available_since_ms=attr_dict['available_since_ms'].default, field_links=attr_dict['field_links'].default):
27    self.signals = signals
28    self.available_since_ms = available_since_ms
29    self.field_links = field_links
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSignalPage.

signals: list[LiveSignal]
available_since_ms: int | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
37    def to_dict(self) -> dict[str, Any]:
38        signals = []
39        for signals_item_data in self.signals:
40            signals_item = signals_item_data.to_dict()
41            signals.append(signals_item)
42
43        available_since_ms = self.available_since_ms
44
45        field_links: dict[str, Any] | Unset = UNSET
46        if not isinstance(self.field_links, Unset):
47            field_links = self.field_links.to_dict()
48
49        field_dict: dict[str, Any] = {}
50        field_dict.update(self.additional_properties)
51        field_dict.update(
52            {
53                "signals": signals,
54            }
55        )
56        if available_since_ms is not UNSET:
57            field_dict["availableSinceMs"] = available_since_ms
58        if field_links is not UNSET:
59            field_dict["_links"] = field_links
60
61        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
63    @classmethod
64    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
65        from ..models.live_signal import LiveSignal
66        from ..models.public_live_list_links import PublicLiveListLinks
67
68        d = dict(src_dict)
69        signals = []
70        _signals = d.pop("signals")
71        for signals_item_data in _signals:
72            signals_item = LiveSignal.from_dict(signals_item_data)
73
74            signals.append(signals_item)
75
76        available_since_ms = d.pop("availableSinceMs", UNSET)
77
78        _field_links = d.pop("_links", UNSET)
79        field_links: PublicLiveListLinks | Unset
80        if isinstance(_field_links, Unset):
81            field_links = UNSET
82        else:
83            field_links = PublicLiveListLinks.from_dict(_field_links)
84
85        live_signal_page = cls(
86            signals=signals,
87            available_since_ms=available_since_ms,
88            field_links=field_links,
89        )
90
91        live_signal_page.additional_properties = d
92        return live_signal_page
additional_keys: list[str]
94    @property
95    def additional_keys(self) -> list[str]:
96        return list(self.additional_properties.keys())
class LiveSignalStage(builtins.str, enum.Enum):
 5class LiveSignalStage(str, Enum):
 6    LIVE = "live"
 7    SANDBOX = "sandbox"
 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'.

LIVE = <LiveSignalStage.LIVE: 'live'>
SANDBOX = <LiveSignalStage.SANDBOX: 'sandbox'>
class LiveSignalType(builtins.str, enum.Enum):
 5class LiveSignalType(str, Enum):
 6    COMMAND = "command"
 7    HINT = "hint"
 8    INFO = "info"
 9    MARKER = "marker"
10    PAPER = "paper"
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'.

COMMAND = <LiveSignalType.COMMAND: 'command'>
HINT = <LiveSignalType.HINT: 'hint'>
INFO = <LiveSignalType.INFO: 'info'>
MARKER = <LiveSignalType.MARKER: 'marker'>
PAPER = <LiveSignalType.PAPER: 'paper'>
class LiveSource:
 15@_attrs_define
 16class LiveSource:
 17    """One market feed a live run consumes. Exactly one entry per run today.
 18
 19    Attributes:
 20        venue_type (str): Venue category. `cx` (centralized exchange) is the only one live runs support today. Example:
 21            cx.
 22        exchange (str):  Example: binance.
 23        segment (str):  Example: spot.
 24        type_ (LiveSourceType): Both `ticker` and `kline` connect to the lightest (fastest) cadence available for the
 25            exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet.
 26        instruments (list[str]): The instruments the run reads. For a run started with a list, that list as sent; for
 27            one started without `instruments`, or with `["*"]`, what the start resolved: the list of pairs the compilation
 28            of the strategy records as the instruments it accepts, when it records one, or `["*"]` for every instrument the
 29            exchange/segment offers (tier-gated). An entry is written `BASE/QUOTE` and either side can be `*` to mean any,
 30            such as any base paired with USDT. Symbols are not case-sensitive and spaces around them are ignored, so
 31            `btc/usdt` and `BTC/USDT` are the same instrument. Example: ['BTC/USDT'].
 32    """
 33
 34    venue_type: str
 35    exchange: str
 36    segment: str
 37    type_: LiveSourceType
 38    instruments: list[str]
 39    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 40
 41    def to_dict(self) -> dict[str, Any]:
 42        venue_type = self.venue_type
 43
 44        exchange = self.exchange
 45
 46        segment = self.segment
 47
 48        type_ = self.type_.value
 49
 50        instruments = self.instruments
 51
 52        field_dict: dict[str, Any] = {}
 53        field_dict.update(self.additional_properties)
 54        field_dict.update(
 55            {
 56                "venueType": venue_type,
 57                "exchange": exchange,
 58                "segment": segment,
 59                "type": type_,
 60                "instruments": instruments,
 61            }
 62        )
 63
 64        return field_dict
 65
 66    @classmethod
 67    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 68        d = dict(src_dict)
 69        venue_type = d.pop("venueType")
 70
 71        exchange = d.pop("exchange")
 72
 73        segment = d.pop("segment")
 74
 75        type_ = LiveSourceType(d.pop("type"))
 76
 77        instruments = cast(list[str], d.pop("instruments"))
 78
 79        live_source = cls(
 80            venue_type=venue_type,
 81            exchange=exchange,
 82            segment=segment,
 83            type_=type_,
 84            instruments=instruments,
 85        )
 86
 87        live_source.additional_properties = d
 88        return live_source
 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

One market feed a live run consumes. Exactly one entry per run today.

Attributes: venue_type (str): Venue category. cx (centralized exchange) is the only one live runs support today. Example: cx. exchange (str): Example: binance. segment (str): Example: spot. type_ (LiveSourceType): Both ticker and kline connect to the lightest (fastest) cadence available for the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet. instruments (list[str]): The instruments the run reads. For a run started with a list, that list as sent; for one started without instruments, or with ["*"], what the start resolved: the list of pairs the compilation of the strategy records as the instruments it accepts, when it records one, or ["*"] for every instrument the exchange/segment offers (tier-gated). An entry is written BASE/QUOTE and either side can be * to mean any, such as any base paired with USDT. Symbols are not case-sensitive and spaces around them are ignored, so btc/usdt and BTC/USDT are the same instrument. Example: ['BTC/USDT'].

LiveSource( venue_type: str, exchange: str, segment: str, type_: LiveSourceType, instruments: list[str])
28def __init__(self, venue_type, exchange, segment, type_, instruments):
29    self.venue_type = venue_type
30    self.exchange = exchange
31    self.segment = segment
32    self.type_ = type_
33    self.instruments = instruments
34    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSource.

venue_type: str
exchange: str
segment: str
instruments: list[str]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
41    def to_dict(self) -> dict[str, Any]:
42        venue_type = self.venue_type
43
44        exchange = self.exchange
45
46        segment = self.segment
47
48        type_ = self.type_.value
49
50        instruments = self.instruments
51
52        field_dict: dict[str, Any] = {}
53        field_dict.update(self.additional_properties)
54        field_dict.update(
55            {
56                "venueType": venue_type,
57                "exchange": exchange,
58                "segment": segment,
59                "type": type_,
60                "instruments": instruments,
61            }
62        )
63
64        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
66    @classmethod
67    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
68        d = dict(src_dict)
69        venue_type = d.pop("venueType")
70
71        exchange = d.pop("exchange")
72
73        segment = d.pop("segment")
74
75        type_ = LiveSourceType(d.pop("type"))
76
77        instruments = cast(list[str], d.pop("instruments"))
78
79        live_source = cls(
80            venue_type=venue_type,
81            exchange=exchange,
82            segment=segment,
83            type_=type_,
84            instruments=instruments,
85        )
86
87        live_source.additional_properties = d
88        return live_source
additional_keys: list[str]
90    @property
91    def additional_keys(self) -> list[str]:
92        return list(self.additional_properties.keys())
class LiveSourceRequest:
 16@_attrs_define
 17class LiveSourceRequest:
 18    """One market feed to start a live run on. Exactly one entry per run today. It is `LiveSource` as you ask for it: the
 19    only difference is that `instruments` can be left out.
 20
 21        Attributes:
 22            venue_type (str): Venue category. `cx` (centralized exchange) is the only one live runs support today. Example:
 23                cx.
 24            exchange (str):  Example: binance.
 25            segment (str):  Example: spot.
 26            type_ (LiveSourceRequestType): Both `ticker` and `kline` connect to the lightest (fastest) cadence available for
 27                the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet.
 28            instruments (list[str] | Unset): Which instruments the run reads. A QTScript strategy can declare which
 29                instruments it accepts with an `instruments` line in its source. When the compilation of the strategy records
 30                that selection as a list of pairs, leaving `instruments` out, or sending `["*"]`, takes that list; otherwise the
 31                run reads every instrument the exchange/segment offers. A list of instruments is taken as sent, and `[]` and
 32                `null` are refused with `400`. An entry is written `BASE/QUOTE`; either side can be `*` to mean any: any base
 33                can be paired with USDT, and BTC can be paired with any quote. Entries are not case-sensitive and spaces around
 34                them are ignored, so `btc/usdt` and `BTC/USDT` are the same instrument. An entry that is not of that form (no
 35                `/`, an empty side, a `.` or a space inside a side, or a `*` mixed with other characters of a side) makes the
 36                run fail when it starts. Plan limits: a list with an entry that has a `*` on a side counts like `["*"]` and only
 37                plans that include the wildcard accept it; the other entries are counted one by one. The instruments the run
 38                actually reads come back in the run's `sources`. Example: ['BTC/USDT'].
 39    """
 40
 41    venue_type: str
 42    exchange: str
 43    segment: str
 44    type_: LiveSourceRequestType
 45    instruments: list[str] | Unset = UNSET
 46    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 47
 48    def to_dict(self) -> dict[str, Any]:
 49        venue_type = self.venue_type
 50
 51        exchange = self.exchange
 52
 53        segment = self.segment
 54
 55        type_ = self.type_.value
 56
 57        instruments: list[str] | Unset = UNSET
 58        if not isinstance(self.instruments, Unset):
 59            instruments = self.instruments
 60
 61        field_dict: dict[str, Any] = {}
 62        field_dict.update(self.additional_properties)
 63        field_dict.update(
 64            {
 65                "venueType": venue_type,
 66                "exchange": exchange,
 67                "segment": segment,
 68                "type": type_,
 69            }
 70        )
 71        if instruments is not UNSET:
 72            field_dict["instruments"] = instruments
 73
 74        return field_dict
 75
 76    @classmethod
 77    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 78        d = dict(src_dict)
 79        venue_type = d.pop("venueType")
 80
 81        exchange = d.pop("exchange")
 82
 83        segment = d.pop("segment")
 84
 85        type_ = LiveSourceRequestType(d.pop("type"))
 86
 87        instruments = cast(list[str], d.pop("instruments", UNSET))
 88
 89        live_source_request = cls(
 90            venue_type=venue_type,
 91            exchange=exchange,
 92            segment=segment,
 93            type_=type_,
 94            instruments=instruments,
 95        )
 96
 97        live_source_request.additional_properties = d
 98        return live_source_request
 99
100    @property
101    def additional_keys(self) -> list[str]:
102        return list(self.additional_properties.keys())
103
104    def __getitem__(self, key: str) -> Any:
105        return self.additional_properties[key]
106
107    def __setitem__(self, key: str, value: Any) -> None:
108        self.additional_properties[key] = value
109
110    def __delitem__(self, key: str) -> None:
111        del self.additional_properties[key]
112
113    def __contains__(self, key: str) -> bool:
114        return key in self.additional_properties

One market feed to start a live run on. Exactly one entry per run today. It is LiveSource as you ask for it: the only difference is that instruments can be left out.

Attributes:
    venue_type (str): Venue category. `cx` (centralized exchange) is the only one live runs support today. Example:
        cx.
    exchange (str):  Example: binance.
    segment (str):  Example: spot.
    type_ (LiveSourceRequestType): Both `ticker` and `kline` connect to the lightest (fastest) cadence available for
        the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet.
    instruments (list[str] | Unset): Which instruments the run reads. A QTScript strategy can declare which
        instruments it accepts with an `instruments` line in its source. When the compilation of the strategy records
        that selection as a list of pairs, leaving `instruments` out, or sending `["*"]`, takes that list; otherwise the
        run reads every instrument the exchange/segment offers. A list of instruments is taken as sent, and `[]` and
        `null` are refused with `400`. An entry is written `BASE/QUOTE`; either side can be `*` to mean any: any base
        can be paired with USDT, and BTC can be paired with any quote. Entries are not case-sensitive and spaces around
        them are ignored, so `btc/usdt` and `BTC/USDT` are the same instrument. An entry that is not of that form (no
        `/`, an empty side, a `.` or a space inside a side, or a `*` mixed with other characters of a side) makes the
        run fail when it starts. Plan limits: a list with an entry that has a `*` on a side counts like `["*"]` and only
        plans that include the wildcard accept it; the other entries are counted one by one. The instruments the run
        actually reads come back in the run's `sources`. Example: ['BTC/USDT'].
LiveSourceRequest( venue_type: str, exchange: str, segment: str, type_: LiveSourceRequestType, instruments: list[str] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
28def __init__(self, venue_type, exchange, segment, type_, instruments=attr_dict['instruments'].default):
29    self.venue_type = venue_type
30    self.exchange = exchange
31    self.segment = segment
32    self.type_ = type_
33    self.instruments = instruments
34    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveSourceRequest.

venue_type: str
exchange: str
segment: str
instruments: list[str] | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
48    def to_dict(self) -> dict[str, Any]:
49        venue_type = self.venue_type
50
51        exchange = self.exchange
52
53        segment = self.segment
54
55        type_ = self.type_.value
56
57        instruments: list[str] | Unset = UNSET
58        if not isinstance(self.instruments, Unset):
59            instruments = self.instruments
60
61        field_dict: dict[str, Any] = {}
62        field_dict.update(self.additional_properties)
63        field_dict.update(
64            {
65                "venueType": venue_type,
66                "exchange": exchange,
67                "segment": segment,
68                "type": type_,
69            }
70        )
71        if instruments is not UNSET:
72            field_dict["instruments"] = instruments
73
74        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
76    @classmethod
77    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
78        d = dict(src_dict)
79        venue_type = d.pop("venueType")
80
81        exchange = d.pop("exchange")
82
83        segment = d.pop("segment")
84
85        type_ = LiveSourceRequestType(d.pop("type"))
86
87        instruments = cast(list[str], d.pop("instruments", UNSET))
88
89        live_source_request = cls(
90            venue_type=venue_type,
91            exchange=exchange,
92            segment=segment,
93            type_=type_,
94            instruments=instruments,
95        )
96
97        live_source_request.additional_properties = d
98        return live_source_request
additional_keys: list[str]
100    @property
101    def additional_keys(self) -> list[str]:
102        return list(self.additional_properties.keys())
class LiveSourceRequestType(builtins.str, enum.Enum):
 5class LiveSourceRequestType(str, Enum):
 6    KLINE = "kline"
 7    TICKER = "ticker"
 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'.

KLINE = <LiveSourceRequestType.KLINE: 'kline'>
TICKER = <LiveSourceRequestType.TICKER: 'ticker'>
class LiveSourceType(builtins.str, enum.Enum):
 5class LiveSourceType(str, Enum):
 6    KLINE = "kline"
 7    TICKER = "ticker"
 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'.

KLINE = <LiveSourceType.KLINE: 'kline'>
TICKER = <LiveSourceType.TICKER: 'ticker'>
class LiveStreamRevoked:
13@_attrs_define
14class LiveStreamRevoked:
15    """What `DELETE /live/{runId}/stream` returns.
16
17    Attributes:
18        run_id (str):
19        revoked (bool): Always `true`.
20    """
21
22    run_id: str
23    revoked: bool
24    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
25
26    def to_dict(self) -> dict[str, Any]:
27        run_id = self.run_id
28
29        revoked = self.revoked
30
31        field_dict: dict[str, Any] = {}
32        field_dict.update(self.additional_properties)
33        field_dict.update(
34            {
35                "runId": run_id,
36                "revoked": revoked,
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        run_id = d.pop("runId")
46
47        revoked = d.pop("revoked")
48
49        live_stream_revoked = cls(
50            run_id=run_id,
51            revoked=revoked,
52        )
53
54        live_stream_revoked.additional_properties = d
55        return live_stream_revoked
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

What DELETE /live/{runId}/stream returns.

Attributes: run_id (str): revoked (bool): Always true.

LiveStreamRevoked(run_id: str, revoked: bool)
25def __init__(self, run_id, revoked):
26    self.run_id = run_id
27    self.revoked = revoked
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveStreamRevoked.

run_id: str
revoked: bool
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
26    def to_dict(self) -> dict[str, Any]:
27        run_id = self.run_id
28
29        revoked = self.revoked
30
31        field_dict: dict[str, Any] = {}
32        field_dict.update(self.additional_properties)
33        field_dict.update(
34            {
35                "runId": run_id,
36                "revoked": revoked,
37            }
38        )
39
40        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
42    @classmethod
43    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
44        d = dict(src_dict)
45        run_id = d.pop("runId")
46
47        revoked = d.pop("revoked")
48
49        live_stream_revoked = cls(
50            run_id=run_id,
51            revoked=revoked,
52        )
53
54        live_stream_revoked.additional_properties = d
55        return live_stream_revoked
additional_keys: list[str]
57    @property
58    def additional_keys(self) -> list[str]:
59        return list(self.additional_properties.keys())
class LiveStreamUrl:
13@_attrs_define
14class LiveStreamUrl:
15    """A run's new stream URL, as returned by `POST /live/{runId}/stream`.
16
17    Attributes:
18        stream_url (str): The run's new secret stream URL. The previous one has stopped working.
19    """
20
21    stream_url: str
22    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
23
24    def to_dict(self) -> dict[str, Any]:
25        stream_url = self.stream_url
26
27        field_dict: dict[str, Any] = {}
28        field_dict.update(self.additional_properties)
29        field_dict.update(
30            {
31                "streamUrl": stream_url,
32            }
33        )
34
35        return field_dict
36
37    @classmethod
38    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
39        d = dict(src_dict)
40        stream_url = d.pop("streamUrl")
41
42        live_stream_url = cls(
43            stream_url=stream_url,
44        )
45
46        live_stream_url.additional_properties = d
47        return live_stream_url
48
49    @property
50    def additional_keys(self) -> list[str]:
51        return list(self.additional_properties.keys())
52
53    def __getitem__(self, key: str) -> Any:
54        return self.additional_properties[key]
55
56    def __setitem__(self, key: str, value: Any) -> None:
57        self.additional_properties[key] = value
58
59    def __delitem__(self, key: str) -> None:
60        del self.additional_properties[key]
61
62    def __contains__(self, key: str) -> bool:
63        return key in self.additional_properties

A run's new stream URL, as returned by POST /live/{runId}/stream.

Attributes: stream_url (str): The run's new secret stream URL. The previous one has stopped working.

LiveStreamUrl(stream_url: str)
24def __init__(self, stream_url):
25    self.stream_url = stream_url
26    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class LiveStreamUrl.

stream_url: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
24    def to_dict(self) -> dict[str, Any]:
25        stream_url = self.stream_url
26
27        field_dict: dict[str, Any] = {}
28        field_dict.update(self.additional_properties)
29        field_dict.update(
30            {
31                "streamUrl": stream_url,
32            }
33        )
34
35        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
37    @classmethod
38    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
39        d = dict(src_dict)
40        stream_url = d.pop("streamUrl")
41
42        live_stream_url = cls(
43            stream_url=stream_url,
44        )
45
46        live_stream_url.additional_properties = d
47        return live_stream_url
additional_keys: list[str]
49    @property
50    def additional_keys(self) -> list[str]:
51        return list(self.additional_properties.keys())
class Notice:
 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.
Notice( level: str, code: str, message: str, provenance: NoticeProvenance | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

level: str
code: str
message: str
provenance: NoticeProvenance | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
90    @property
91    def additional_keys(self) -> list[str]:
92        return list(self.additional_properties.keys())
class NoticeProvenance(builtins.str, enum.Enum):
 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'.

COMPILE_DRY_RUN = <NoticeProvenance.COMPILE_DRY_RUN: 'compile-dry-run'>
EXECUTE = <NoticeProvenance.EXECUTE: 'execute'>
class PrepareJobState:
 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` are present either way, and
 36    `coverageRatio` too, computed accordingly — except against a dataset whose `cadence` is `rt`:
 37    with no fixed step there is no expected row count to measure against, so `coverageRatio`
 38    is absent and `gaps`/`largestGapSteps` are `0`.
 39
 40        Attributes:
 41            context_id (str): Identifier for the job's execution context. Its current shape is a colon-delimited string
 42                encoding the data source type, an internal user id, the exchange, the job id, and the instrument — but that
 43                structure is not a committed contract and may change without notice. Treat it as an opaque token: store and pass
 44                it back, don't parse it. Example:
 45                jctx:ticker:00000000-0000-0000-0000-000000000000:binance:5ikyamio8b3v9wcnfxztzg:btc/usdt:0vicnz3thzhrqvfczks1pu.
 46            status (JobStateStatus): Current status of the job. Treat `Completed | Aborted | Failed` as
 47                terminal; `New | Started` mean keep polling. A single-instrument prepare
 48                is always terminal (`Completed`) — decide from
 49                `PrepareJobState.coverageRatio` (or `dataFrom`/`dataTo` against an `rt` dataset,
 50                which has no ratio), not by polling.
 51                 Example: Completed.
 52            size (int): Total size of the data being prepared Example: 100.
 53            completed (int): The amount of data processed so far Example: 50.
 54            status_detail (None | str | Unset): Detailed status information, if available Example: Job completed with error
 55                code 5001.
 56            start_time (datetime.datetime | None | Unset): Timestamp for when the preparation started Example:
 57                2025-01-04T14:00:00Z.
 58            end_time (datetime.datetime | None | Unset): Timestamp for when the preparation finished Example:
 59                2025-01-04T14:00:20Z.
 60            data_from (datetime.datetime | None | Unset): Start of the available data range for the prepared instrument.
 61                Example: 2026-04-14T13:00:00Z.
 62            data_to (datetime.datetime | None | Unset): End of the available data range for the prepared instrument.
 63                Example: 2026-04-14T15:30:05Z.
 64            coverage_ratio (float | Unset): Against a managed exchange: `hoursWithData / totalHours` in `[0,1]` (`1.0` when
 65                `totalHours` is 0), the fraction of hours in the requested range that have served
 66                data. Against a dataset (`exchangeId: user`): `rows / expectedStepsAtCadence`
 67                over the dataset version's own range — echoing what ingest computed once, not
 68                recomputed against a narrower prepare request. Absent for an `rt` dataset (no
 69                fixed step, so no expected row count).
 70                 Example: 0.994.
 71            total_hours (int | Unset): Number of whole hours in the requested prepare range. Managed exchanges only —
 72                absent for a dataset-backed prepare.
 73                 Example: 168.
 74            hours_with_data (int | Unset): Number of hours in the range that have data. Managed exchanges only — absent for
 75                a dataset-backed prepare.
 76                 Example: 167.
 77            cadence (str | Unset): The dataset version's own discovered cadence — a fixed grid (e.g. `1m`, `1h`) or
 78                `rt` (see `DatasetVersion.cadence`). Only present for a dataset-backed prepare
 79                (`exchangeId: user`).
 80                 Example: 1m.
 81            gaps (int | Unset): Number of gaps in the dataset version at its own cadence, as discovered at ingest
 82                time. `0` for `rt`. Only present for a dataset-backed prepare.
 83            largest_gap_steps (int | Unset): The largest gap in the dataset version, in units of its own cadence step. `0`
 84                for
 85                `rt`. Only present for a dataset-backed prepare.
 86            hours_without_data (list[PrepareJobStateHoursWithoutDataItem] | Unset): One entry per hour in the range that has
 87                no data, with a rationale. Managed
 88                exchanges only — absent for a dataset-backed prepare.
 89    """
 90
 91    context_id: str
 92    status: JobStateStatus
 93    size: int
 94    completed: int
 95    status_detail: None | str | Unset = UNSET
 96    start_time: datetime.datetime | None | Unset = UNSET
 97    end_time: datetime.datetime | None | Unset = UNSET
 98    data_from: datetime.datetime | None | Unset = UNSET
 99    data_to: datetime.datetime | None | Unset = UNSET
100    coverage_ratio: float | Unset = UNSET
101    total_hours: int | Unset = UNSET
102    hours_with_data: int | Unset = UNSET
103    cadence: str | Unset = UNSET
104    gaps: int | Unset = UNSET
105    largest_gap_steps: int | Unset = UNSET
106    hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | Unset = UNSET
107    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
108
109    def to_dict(self) -> dict[str, Any]:
110        context_id = self.context_id
111
112        status = self.status.value
113
114        size = self.size
115
116        completed = self.completed
117
118        status_detail: None | str | Unset
119        if isinstance(self.status_detail, Unset):
120            status_detail = UNSET
121        else:
122            status_detail = self.status_detail
123
124        start_time: None | str | Unset
125        if isinstance(self.start_time, Unset):
126            start_time = UNSET
127        elif isinstance(self.start_time, datetime.datetime):
128            start_time = self.start_time.isoformat()
129        else:
130            start_time = self.start_time
131
132        end_time: None | str | Unset
133        if isinstance(self.end_time, Unset):
134            end_time = UNSET
135        elif isinstance(self.end_time, datetime.datetime):
136            end_time = self.end_time.isoformat()
137        else:
138            end_time = self.end_time
139
140        data_from: None | str | Unset
141        if isinstance(self.data_from, Unset):
142            data_from = UNSET
143        elif isinstance(self.data_from, datetime.datetime):
144            data_from = self.data_from.isoformat()
145        else:
146            data_from = self.data_from
147
148        data_to: None | str | Unset
149        if isinstance(self.data_to, Unset):
150            data_to = UNSET
151        elif isinstance(self.data_to, datetime.datetime):
152            data_to = self.data_to.isoformat()
153        else:
154            data_to = self.data_to
155
156        coverage_ratio = self.coverage_ratio
157
158        total_hours = self.total_hours
159
160        hours_with_data = self.hours_with_data
161
162        cadence = self.cadence
163
164        gaps = self.gaps
165
166        largest_gap_steps = self.largest_gap_steps
167
168        hours_without_data: list[dict[str, Any]] | Unset = UNSET
169        if not isinstance(self.hours_without_data, Unset):
170            hours_without_data = []
171            for hours_without_data_item_data in self.hours_without_data:
172                hours_without_data_item = hours_without_data_item_data.to_dict()
173                hours_without_data.append(hours_without_data_item)
174
175        field_dict: dict[str, Any] = {}
176        field_dict.update(self.additional_properties)
177        field_dict.update(
178            {
179                "contextId": context_id,
180                "status": status,
181                "size": size,
182                "completed": completed,
183            }
184        )
185        if status_detail is not UNSET:
186            field_dict["statusDetail"] = status_detail
187        if start_time is not UNSET:
188            field_dict["startTime"] = start_time
189        if end_time is not UNSET:
190            field_dict["endTime"] = end_time
191        if data_from is not UNSET:
192            field_dict["dataFrom"] = data_from
193        if data_to is not UNSET:
194            field_dict["dataTo"] = data_to
195        if coverage_ratio is not UNSET:
196            field_dict["coverageRatio"] = coverage_ratio
197        if total_hours is not UNSET:
198            field_dict["totalHours"] = total_hours
199        if hours_with_data is not UNSET:
200            field_dict["hoursWithData"] = hours_with_data
201        if cadence is not UNSET:
202            field_dict["cadence"] = cadence
203        if gaps is not UNSET:
204            field_dict["gaps"] = gaps
205        if largest_gap_steps is not UNSET:
206            field_dict["largestGapSteps"] = largest_gap_steps
207        if hours_without_data is not UNSET:
208            field_dict["hoursWithoutData"] = hours_without_data
209
210        return field_dict
211
212    @classmethod
213    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
214        from ..models.prepare_job_state_hours_without_data_item import PrepareJobStateHoursWithoutDataItem
215
216        d = dict(src_dict)
217        context_id = d.pop("contextId")
218
219        status = JobStateStatus(d.pop("status"))
220
221        size = d.pop("size")
222
223        completed = d.pop("completed")
224
225        def _parse_status_detail(data: object) -> None | str | Unset:
226            if data is None:
227                return data
228            if isinstance(data, Unset):
229                return data
230            return cast(None | str | Unset, data)
231
232        status_detail = _parse_status_detail(d.pop("statusDetail", UNSET))
233
234        def _parse_start_time(data: object) -> datetime.datetime | None | Unset:
235            if data is None:
236                return data
237            if isinstance(data, Unset):
238                return data
239            try:
240                if not isinstance(data, str):
241                    raise TypeError()
242                start_time_type_0 = isoparse(data)
243
244                return start_time_type_0
245            except (TypeError, ValueError, AttributeError, KeyError):
246                pass
247            return cast(datetime.datetime | None | Unset, data)
248
249        start_time = _parse_start_time(d.pop("startTime", UNSET))
250
251        def _parse_end_time(data: object) -> datetime.datetime | None | Unset:
252            if data is None:
253                return data
254            if isinstance(data, Unset):
255                return data
256            try:
257                if not isinstance(data, str):
258                    raise TypeError()
259                end_time_type_0 = isoparse(data)
260
261                return end_time_type_0
262            except (TypeError, ValueError, AttributeError, KeyError):
263                pass
264            return cast(datetime.datetime | None | Unset, data)
265
266        end_time = _parse_end_time(d.pop("endTime", UNSET))
267
268        def _parse_data_from(data: object) -> datetime.datetime | None | Unset:
269            if data is None:
270                return data
271            if isinstance(data, Unset):
272                return data
273            try:
274                if not isinstance(data, str):
275                    raise TypeError()
276                data_from_type_0 = isoparse(data)
277
278                return data_from_type_0
279            except (TypeError, ValueError, AttributeError, KeyError):
280                pass
281            return cast(datetime.datetime | None | Unset, data)
282
283        data_from = _parse_data_from(d.pop("dataFrom", UNSET))
284
285        def _parse_data_to(data: object) -> datetime.datetime | None | Unset:
286            if data is None:
287                return data
288            if isinstance(data, Unset):
289                return data
290            try:
291                if not isinstance(data, str):
292                    raise TypeError()
293                data_to_type_0 = isoparse(data)
294
295                return data_to_type_0
296            except (TypeError, ValueError, AttributeError, KeyError):
297                pass
298            return cast(datetime.datetime | None | Unset, data)
299
300        data_to = _parse_data_to(d.pop("dataTo", UNSET))
301
302        coverage_ratio = d.pop("coverageRatio", UNSET)
303
304        total_hours = d.pop("totalHours", UNSET)
305
306        hours_with_data = d.pop("hoursWithData", UNSET)
307
308        cadence = d.pop("cadence", UNSET)
309
310        gaps = d.pop("gaps", UNSET)
311
312        largest_gap_steps = d.pop("largestGapSteps", UNSET)
313
314        _hours_without_data = d.pop("hoursWithoutData", UNSET)
315        hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | Unset = UNSET
316        if _hours_without_data is not UNSET:
317            hours_without_data = []
318            for hours_without_data_item_data in _hours_without_data:
319                hours_without_data_item = PrepareJobStateHoursWithoutDataItem.from_dict(hours_without_data_item_data)
320
321                hours_without_data.append(hours_without_data_item)
322
323        prepare_job_state = cls(
324            context_id=context_id,
325            status=status,
326            size=size,
327            completed=completed,
328            status_detail=status_detail,
329            start_time=start_time,
330            end_time=end_time,
331            data_from=data_from,
332            data_to=data_to,
333            coverage_ratio=coverage_ratio,
334            total_hours=total_hours,
335            hours_with_data=hours_with_data,
336            cadence=cadence,
337            gaps=gaps,
338            largest_gap_steps=largest_gap_steps,
339            hours_without_data=hours_without_data,
340        )
341
342        prepare_job_state.additional_properties = d
343        return prepare_job_state
344
345    @property
346    def additional_keys(self) -> list[str]:
347        return list(self.additional_properties.keys())
348
349    def __getitem__(self, key: str) -> Any:
350        return self.additional_properties[key]
351
352    def __setitem__(self, key: str, value: Any) -> None:
353        self.additional_properties[key] = value
354
355    def __delitem__(self, key: str) -> None:
356        del self.additional_properties[key]
357
358    def __contains__(self, key: str) -> bool:
359        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 are present either way, and coverageRatio too, computed accordingly — except against a dataset whose cadence is rt: with no fixed step there is no expected row count to measure against, so coverageRatio is absent and gaps/largestGapSteps are 0.

Attributes:
    context_id (str): Identifier for the job's execution context. Its current shape is a colon-delimited string
        encoding the data source type, an internal user id, the exchange, the job id, and the instrument — but that
        structure is not a committed contract and may change without notice. Treat it as an opaque token: store and pass
        it back, don't parse it. Example:
        jctx:ticker:00000000-0000-0000-0000-000000000000:binance:5ikyamio8b3v9wcnfxztzg:btc/usdt:0vicnz3thzhrqvfczks1pu.
    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` (or `dataFrom`/`dataTo` against an `rt` dataset,
        which has no ratio), 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. Absent for an `rt` dataset (no
        fixed step, so no expected row count).
         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 — a fixed grid (e.g. `1m`, `1h`) or
        `rt` (see `DatasetVersion.cadence`). 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. `0` for `rt`. 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. `0`
        for
        `rt`. 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.
PrepareJobState( context_id: str, status: JobStateStatus, size: int, completed: int, status_detail: None | str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, start_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, end_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, data_from: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, data_to: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, coverage_ratio: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, total_hours: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, hours_with_data: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cadence: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, gaps: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, largest_gap_steps: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

context_id: str
status: JobStateStatus
size: int
completed: int
status_detail: None | str | qtsurfer.api.client._generated.types.Unset
start_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset
end_time: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset
data_from: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset
data_to: datetime.datetime | None | qtsurfer.api.client._generated.types.Unset
coverage_ratio: float | qtsurfer.api.client._generated.types.Unset
total_hours: int | qtsurfer.api.client._generated.types.Unset
hours_with_data: int | qtsurfer.api.client._generated.types.Unset
cadence: str | qtsurfer.api.client._generated.types.Unset
gaps: int | qtsurfer.api.client._generated.types.Unset
largest_gap_steps: int | qtsurfer.api.client._generated.types.Unset
hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
109    def to_dict(self) -> dict[str, Any]:
110        context_id = self.context_id
111
112        status = self.status.value
113
114        size = self.size
115
116        completed = self.completed
117
118        status_detail: None | str | Unset
119        if isinstance(self.status_detail, Unset):
120            status_detail = UNSET
121        else:
122            status_detail = self.status_detail
123
124        start_time: None | str | Unset
125        if isinstance(self.start_time, Unset):
126            start_time = UNSET
127        elif isinstance(self.start_time, datetime.datetime):
128            start_time = self.start_time.isoformat()
129        else:
130            start_time = self.start_time
131
132        end_time: None | str | Unset
133        if isinstance(self.end_time, Unset):
134            end_time = UNSET
135        elif isinstance(self.end_time, datetime.datetime):
136            end_time = self.end_time.isoformat()
137        else:
138            end_time = self.end_time
139
140        data_from: None | str | Unset
141        if isinstance(self.data_from, Unset):
142            data_from = UNSET
143        elif isinstance(self.data_from, datetime.datetime):
144            data_from = self.data_from.isoformat()
145        else:
146            data_from = self.data_from
147
148        data_to: None | str | Unset
149        if isinstance(self.data_to, Unset):
150            data_to = UNSET
151        elif isinstance(self.data_to, datetime.datetime):
152            data_to = self.data_to.isoformat()
153        else:
154            data_to = self.data_to
155
156        coverage_ratio = self.coverage_ratio
157
158        total_hours = self.total_hours
159
160        hours_with_data = self.hours_with_data
161
162        cadence = self.cadence
163
164        gaps = self.gaps
165
166        largest_gap_steps = self.largest_gap_steps
167
168        hours_without_data: list[dict[str, Any]] | Unset = UNSET
169        if not isinstance(self.hours_without_data, Unset):
170            hours_without_data = []
171            for hours_without_data_item_data in self.hours_without_data:
172                hours_without_data_item = hours_without_data_item_data.to_dict()
173                hours_without_data.append(hours_without_data_item)
174
175        field_dict: dict[str, Any] = {}
176        field_dict.update(self.additional_properties)
177        field_dict.update(
178            {
179                "contextId": context_id,
180                "status": status,
181                "size": size,
182                "completed": completed,
183            }
184        )
185        if status_detail is not UNSET:
186            field_dict["statusDetail"] = status_detail
187        if start_time is not UNSET:
188            field_dict["startTime"] = start_time
189        if end_time is not UNSET:
190            field_dict["endTime"] = end_time
191        if data_from is not UNSET:
192            field_dict["dataFrom"] = data_from
193        if data_to is not UNSET:
194            field_dict["dataTo"] = data_to
195        if coverage_ratio is not UNSET:
196            field_dict["coverageRatio"] = coverage_ratio
197        if total_hours is not UNSET:
198            field_dict["totalHours"] = total_hours
199        if hours_with_data is not UNSET:
200            field_dict["hoursWithData"] = hours_with_data
201        if cadence is not UNSET:
202            field_dict["cadence"] = cadence
203        if gaps is not UNSET:
204            field_dict["gaps"] = gaps
205        if largest_gap_steps is not UNSET:
206            field_dict["largestGapSteps"] = largest_gap_steps
207        if hours_without_data is not UNSET:
208            field_dict["hoursWithoutData"] = hours_without_data
209
210        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
212    @classmethod
213    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
214        from ..models.prepare_job_state_hours_without_data_item import PrepareJobStateHoursWithoutDataItem
215
216        d = dict(src_dict)
217        context_id = d.pop("contextId")
218
219        status = JobStateStatus(d.pop("status"))
220
221        size = d.pop("size")
222
223        completed = d.pop("completed")
224
225        def _parse_status_detail(data: object) -> None | str | Unset:
226            if data is None:
227                return data
228            if isinstance(data, Unset):
229                return data
230            return cast(None | str | Unset, data)
231
232        status_detail = _parse_status_detail(d.pop("statusDetail", UNSET))
233
234        def _parse_start_time(data: object) -> datetime.datetime | None | Unset:
235            if data is None:
236                return data
237            if isinstance(data, Unset):
238                return data
239            try:
240                if not isinstance(data, str):
241                    raise TypeError()
242                start_time_type_0 = isoparse(data)
243
244                return start_time_type_0
245            except (TypeError, ValueError, AttributeError, KeyError):
246                pass
247            return cast(datetime.datetime | None | Unset, data)
248
249        start_time = _parse_start_time(d.pop("startTime", UNSET))
250
251        def _parse_end_time(data: object) -> datetime.datetime | None | Unset:
252            if data is None:
253                return data
254            if isinstance(data, Unset):
255                return data
256            try:
257                if not isinstance(data, str):
258                    raise TypeError()
259                end_time_type_0 = isoparse(data)
260
261                return end_time_type_0
262            except (TypeError, ValueError, AttributeError, KeyError):
263                pass
264            return cast(datetime.datetime | None | Unset, data)
265
266        end_time = _parse_end_time(d.pop("endTime", UNSET))
267
268        def _parse_data_from(data: object) -> datetime.datetime | None | Unset:
269            if data is None:
270                return data
271            if isinstance(data, Unset):
272                return data
273            try:
274                if not isinstance(data, str):
275                    raise TypeError()
276                data_from_type_0 = isoparse(data)
277
278                return data_from_type_0
279            except (TypeError, ValueError, AttributeError, KeyError):
280                pass
281            return cast(datetime.datetime | None | Unset, data)
282
283        data_from = _parse_data_from(d.pop("dataFrom", UNSET))
284
285        def _parse_data_to(data: object) -> datetime.datetime | None | Unset:
286            if data is None:
287                return data
288            if isinstance(data, Unset):
289                return data
290            try:
291                if not isinstance(data, str):
292                    raise TypeError()
293                data_to_type_0 = isoparse(data)
294
295                return data_to_type_0
296            except (TypeError, ValueError, AttributeError, KeyError):
297                pass
298            return cast(datetime.datetime | None | Unset, data)
299
300        data_to = _parse_data_to(d.pop("dataTo", UNSET))
301
302        coverage_ratio = d.pop("coverageRatio", UNSET)
303
304        total_hours = d.pop("totalHours", UNSET)
305
306        hours_with_data = d.pop("hoursWithData", UNSET)
307
308        cadence = d.pop("cadence", UNSET)
309
310        gaps = d.pop("gaps", UNSET)
311
312        largest_gap_steps = d.pop("largestGapSteps", UNSET)
313
314        _hours_without_data = d.pop("hoursWithoutData", UNSET)
315        hours_without_data: list[PrepareJobStateHoursWithoutDataItem] | Unset = UNSET
316        if _hours_without_data is not UNSET:
317            hours_without_data = []
318            for hours_without_data_item_data in _hours_without_data:
319                hours_without_data_item = PrepareJobStateHoursWithoutDataItem.from_dict(hours_without_data_item_data)
320
321                hours_without_data.append(hours_without_data_item)
322
323        prepare_job_state = cls(
324            context_id=context_id,
325            status=status,
326            size=size,
327            completed=completed,
328            status_detail=status_detail,
329            start_time=start_time,
330            end_time=end_time,
331            data_from=data_from,
332            data_to=data_to,
333            coverage_ratio=coverage_ratio,
334            total_hours=total_hours,
335            hours_with_data=hours_with_data,
336            cadence=cadence,
337            gaps=gaps,
338            largest_gap_steps=largest_gap_steps,
339            hours_without_data=hours_without_data,
340        )
341
342        prepare_job_state.additional_properties = d
343        return prepare_job_state
additional_keys: list[str]
345    @property
346    def additional_keys(self) -> list[str]:
347        return list(self.additional_properties.keys())
class PrepareJobStateHoursWithoutDataItem:
 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.

PrepareJobStateHoursWithoutDataItem( hour: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, expected: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, rationale: PrepareJobStateHoursWithoutDataItemRationale | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

hour: datetime.datetime | qtsurfer.api.client._generated.types.Unset
expected: int | qtsurfer.api.client._generated.types.Unset
rationale: PrepareJobStateHoursWithoutDataItemRationale | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
88    @property
89    def additional_keys(self) -> list[str]:
90        return list(self.additional_properties.keys())
class PrepareJobStateHoursWithoutDataItemRationale(builtins.str, enum.Enum):
 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'.

PENDING_CONVERSION = <PrepareJobStateHoursWithoutDataItemRationale.PENDING_CONVERSION: 'pending_conversion'>
class PrepareRequest:
 15@_attrs_define
 16class PrepareRequest:
 17    """Two shapes, chosen by the `exchangeId` path segment. Against a managed exchange,
 18    `instrument` is required and `datasetId`/`datasetVersionId` are ignored. Against the
 19    reserved `exchangeId: user`, send `datasetId` instead of `instrument` — `instrument` is
 20    ignored there, since it comes from the dataset itself.
 21
 22        Example:
 23            {'instrument': 'BTC/USDT', 'from': '2024-12-13T00:00:00Z', 'to': '2024-12-14T00:00:00Z', 'cadence': '1m'}
 24
 25        Attributes:
 26            from_ (str): Start date for the preparation process. Supports the following formats:
 27                - ISO-8601 (e.g. 2024-12-14T23:59:59Z)
 28                - ISO DATE (e.g. 2024-12-14)
 29                - BASIC ISO DATE (e.g., 20241214)
 30                 Example: 2024-12-13T00:00:00Z.
 31            to (str): End date for the preparation process. Supports the following formats:
 32                - ISO-8601 (e.g. 2024-12-14T23:59:59Z)
 33                - ISO DATE (e.g. 2024-12-14)
 34                - BASIC ISO DATE (e.g., 20241214)
 35                 Example: 2024-12-14.
 36            instrument (str | Unset): Exchange instrument identifier (e.g. a currency pair) Example: BTC/USDT.
 37            dataset_id (str | Unset): Only for `exchangeId: user`: the id of a dataset created via `POST /datasets`, in
 38                place
 39                of `instrument`. Ignored against a managed exchange.
 40                 Example: ds_3f9a1c2e7b0d4a5f.
 41            dataset_version_id (str | Unset): Only for `exchangeId: user`, and optional even then: pins a specific past
 42                version of
 43                the dataset instead of its current one. Defaults to the dataset's current version.
 44                 Example: dsv_8e2b4f19c6a03d7e.
 45            cadence (str | Unset): Output bar cadence for the prepared range. Coarser cadences are produced on demand by
 46                resampling the source and stored alongside the native blob in cache. A target finer
 47                than the source, or not an exact multiple of it, returns `400`. What's accepted, and
 48                what omitting it means, depends on the source:
 49
 50                * Managed exchange, `ticker` or `funding` — one of `1s`, `5s`, `1m`, `3m`, `5m`, `15m`,
 51                  `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, `1d`, `1w`, `1q`; any other label returns `400`.
 52                  Omitted = `1s`, the publisher's native cadence.
 53                * Managed exchange, `kline` — one of `1s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d`;
 54                  any other label, including `5s`, `3m` and `8h`, returns `400` and names the accepted
 55                  ones. Omitted = `1s`. This is the width of the bars a run reads: it is chosen here,
 56                  once, and the same strategy can be run at several cadences by preparing the range at
 57                  each.
 58                * Dataset (`exchangeId: user`) — omitted = the dataset version's own discovered
 59                  `cadence` (see `DatasetVersion.cadence`), served as-is. Any cadence equal to or
 60                  coarser than it and an exact multiple of it is accepted, including ones outside the
 61                  managed-exchange list (e.g. `15s`); an `rt` dataset can be resampled to any fixed
 62                  cadence.
 63    """
 64
 65    from_: str
 66    to: str
 67    instrument: str | Unset = UNSET
 68    dataset_id: str | Unset = UNSET
 69    dataset_version_id: str | Unset = UNSET
 70    cadence: str | Unset = UNSET
 71    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 72
 73    def to_dict(self) -> dict[str, Any]:
 74        from_ = self.from_
 75
 76        to = self.to
 77
 78        instrument = self.instrument
 79
 80        dataset_id = self.dataset_id
 81
 82        dataset_version_id = self.dataset_version_id
 83
 84        cadence = self.cadence
 85
 86        field_dict: dict[str, Any] = {}
 87        field_dict.update(self.additional_properties)
 88        field_dict.update(
 89            {
 90                "from": from_,
 91                "to": to,
 92            }
 93        )
 94        if instrument is not UNSET:
 95            field_dict["instrument"] = instrument
 96        if dataset_id is not UNSET:
 97            field_dict["datasetId"] = dataset_id
 98        if dataset_version_id is not UNSET:
 99            field_dict["datasetVersionId"] = dataset_version_id
100        if cadence is not UNSET:
101            field_dict["cadence"] = cadence
102
103        return field_dict
104
105    @classmethod
106    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
107        d = dict(src_dict)
108        from_ = d.pop("from")
109
110        to = d.pop("to")
111
112        instrument = d.pop("instrument", UNSET)
113
114        dataset_id = d.pop("datasetId", UNSET)
115
116        dataset_version_id = d.pop("datasetVersionId", UNSET)
117
118        cadence = d.pop("cadence", UNSET)
119
120        prepare_request = cls(
121            from_=from_,
122            to=to,
123            instrument=instrument,
124            dataset_id=dataset_id,
125            dataset_version_id=dataset_version_id,
126            cadence=cadence,
127        )
128
129        prepare_request.additional_properties = d
130        return prepare_request
131
132    @property
133    def additional_keys(self) -> list[str]:
134        return list(self.additional_properties.keys())
135
136    def __getitem__(self, key: str) -> Any:
137        return self.additional_properties[key]
138
139    def __setitem__(self, key: str, value: Any) -> None:
140        self.additional_properties[key] = value
141
142    def __delitem__(self, key: str) -> None:
143        del self.additional_properties[key]
144
145    def __contains__(self, key: str) -> bool:
146        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 (str | Unset): Output bar cadence for the prepared range. Coarser cadences are produced on demand by
        resampling the source and stored alongside the native blob in cache. A target finer
        than the source, or not an exact multiple of it, returns `400`. What's accepted, and
        what omitting it means, depends on the source:

        * Managed exchange, `ticker` or `funding` — one of `1s`, `5s`, `1m`, `3m`, `5m`, `15m`,
          `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, `1d`, `1w`, `1q`; any other label returns `400`.
          Omitted = `1s`, the publisher's native cadence.
        * Managed exchange, `kline` — one of `1s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d`;
          any other label, including `5s`, `3m` and `8h`, returns `400` and names the accepted
          ones. Omitted = `1s`. This is the width of the bars a run reads: it is chosen here,
          once, and the same strategy can be run at several cadences by preparing the range at
          each.
        * Dataset (`exchangeId: user`) — omitted = the dataset version's own discovered
          `cadence` (see `DatasetVersion.cadence`), served as-is. Any cadence equal to or
          coarser than it and an exact multiple of it is accepted, including ones outside the
          managed-exchange list (e.g. `15s`); an `rt` dataset can be resampled to any fixed
          cadence.
PrepareRequest( from_: str, to: str, instrument: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, dataset_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, dataset_version_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cadence: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

from_: str
to: str
instrument: str | qtsurfer.api.client._generated.types.Unset
dataset_id: str | qtsurfer.api.client._generated.types.Unset
dataset_version_id: str | qtsurfer.api.client._generated.types.Unset
cadence: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 73    def to_dict(self) -> dict[str, Any]:
 74        from_ = self.from_
 75
 76        to = self.to
 77
 78        instrument = self.instrument
 79
 80        dataset_id = self.dataset_id
 81
 82        dataset_version_id = self.dataset_version_id
 83
 84        cadence = self.cadence
 85
 86        field_dict: dict[str, Any] = {}
 87        field_dict.update(self.additional_properties)
 88        field_dict.update(
 89            {
 90                "from": from_,
 91                "to": to,
 92            }
 93        )
 94        if instrument is not UNSET:
 95            field_dict["instrument"] = instrument
 96        if dataset_id is not UNSET:
 97            field_dict["datasetId"] = dataset_id
 98        if dataset_version_id is not UNSET:
 99            field_dict["datasetVersionId"] = dataset_version_id
100        if cadence is not UNSET:
101            field_dict["cadence"] = cadence
102
103        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
105    @classmethod
106    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
107        d = dict(src_dict)
108        from_ = d.pop("from")
109
110        to = d.pop("to")
111
112        instrument = d.pop("instrument", UNSET)
113
114        dataset_id = d.pop("datasetId", UNSET)
115
116        dataset_version_id = d.pop("datasetVersionId", UNSET)
117
118        cadence = d.pop("cadence", UNSET)
119
120        prepare_request = cls(
121            from_=from_,
122            to=to,
123            instrument=instrument,
124            dataset_id=dataset_id,
125            dataset_version_id=dataset_version_id,
126            cadence=cadence,
127        )
128
129        prepare_request.additional_properties = d
130        return prepare_request
additional_keys: list[str]
132    @property
133    def additional_keys(self) -> list[str]:
134        return list(self.additional_properties.keys())
class PublicLiveListResponse:
20@_attrs_define
21class PublicLiveListResponse:
22    """
23    Attributes:
24        runs (list[PublicLiveRun]):
25        field_links (PublicLiveListLinks | Unset): Present only when another page exists.
26    """
27
28    runs: list[PublicLiveRun]
29    field_links: PublicLiveListLinks | Unset = UNSET
30    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
31
32    def to_dict(self) -> dict[str, Any]:
33        runs = []
34        for runs_item_data in self.runs:
35            runs_item = runs_item_data.to_dict()
36            runs.append(runs_item)
37
38        field_links: dict[str, Any] | Unset = UNSET
39        if not isinstance(self.field_links, Unset):
40            field_links = self.field_links.to_dict()
41
42        field_dict: dict[str, Any] = {}
43        field_dict.update(self.additional_properties)
44        field_dict.update(
45            {
46                "runs": runs,
47            }
48        )
49        if field_links is not UNSET:
50            field_dict["_links"] = field_links
51
52        return field_dict
53
54    @classmethod
55    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
56        from ..models.public_live_list_links import PublicLiveListLinks
57        from ..models.public_live_run import PublicLiveRun
58
59        d = dict(src_dict)
60        runs = []
61        _runs = d.pop("runs")
62        for runs_item_data in _runs:
63            runs_item = PublicLiveRun.from_dict(runs_item_data)
64
65            runs.append(runs_item)
66
67        _field_links = d.pop("_links", UNSET)
68        field_links: PublicLiveListLinks | Unset
69        if isinstance(_field_links, Unset):
70            field_links = UNSET
71        else:
72            field_links = PublicLiveListLinks.from_dict(_field_links)
73
74        public_live_list_response = cls(
75            runs=runs,
76            field_links=field_links,
77        )
78
79        public_live_list_response.additional_properties = d
80        return public_live_list_response
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: runs (list[PublicLiveRun]): field_links (PublicLiveListLinks | Unset): Present only when another page exists.

PublicLiveListResponse( runs: list[PublicLiveRun], field_links: PublicLiveListLinks | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
25def __init__(self, runs, field_links=attr_dict['field_links'].default):
26    self.runs = runs
27    self.field_links = field_links
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class PublicLiveListResponse.

runs: list[PublicLiveRun]
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
32    def to_dict(self) -> dict[str, Any]:
33        runs = []
34        for runs_item_data in self.runs:
35            runs_item = runs_item_data.to_dict()
36            runs.append(runs_item)
37
38        field_links: dict[str, Any] | Unset = UNSET
39        if not isinstance(self.field_links, Unset):
40            field_links = self.field_links.to_dict()
41
42        field_dict: dict[str, Any] = {}
43        field_dict.update(self.additional_properties)
44        field_dict.update(
45            {
46                "runs": runs,
47            }
48        )
49        if field_links is not UNSET:
50            field_dict["_links"] = field_links
51
52        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
54    @classmethod
55    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
56        from ..models.public_live_list_links import PublicLiveListLinks
57        from ..models.public_live_run import PublicLiveRun
58
59        d = dict(src_dict)
60        runs = []
61        _runs = d.pop("runs")
62        for runs_item_data in _runs:
63            runs_item = PublicLiveRun.from_dict(runs_item_data)
64
65            runs.append(runs_item)
66
67        _field_links = d.pop("_links", UNSET)
68        field_links: PublicLiveListLinks | Unset
69        if isinstance(_field_links, Unset):
70            field_links = UNSET
71        else:
72            field_links = PublicLiveListLinks.from_dict(_field_links)
73
74        public_live_list_response = cls(
75            runs=runs,
76            field_links=field_links,
77        )
78
79        public_live_list_response.additional_properties = d
80        return public_live_list_response
additional_keys: list[str]
82    @property
83    def additional_keys(self) -> list[str]:
84        return list(self.additional_properties.keys())
class PublicLiveRun:
 19@_attrs_define
 20class PublicLiveRun:
 21    """A run as it appears in `GET /live/public` — never reveals who owns it or which strategy it runs.
 22
 23    Attributes:
 24        run_id (str):
 25        sources (list[LiveSource]):
 26        state (str):
 27        created_at_ms (int):
 28        name (str | Unset):
 29        description (str | Unset):
 30    """
 31
 32    run_id: str
 33    sources: list[LiveSource]
 34    state: str
 35    created_at_ms: int
 36    name: str | Unset = UNSET
 37    description: str | Unset = UNSET
 38    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 39
 40    def to_dict(self) -> dict[str, Any]:
 41        run_id = self.run_id
 42
 43        sources = []
 44        for sources_item_data in self.sources:
 45            sources_item = sources_item_data.to_dict()
 46            sources.append(sources_item)
 47
 48        state = self.state
 49
 50        created_at_ms = self.created_at_ms
 51
 52        name = self.name
 53
 54        description = self.description
 55
 56        field_dict: dict[str, Any] = {}
 57        field_dict.update(self.additional_properties)
 58        field_dict.update(
 59            {
 60                "runId": run_id,
 61                "sources": sources,
 62                "state": state,
 63                "createdAtMs": created_at_ms,
 64            }
 65        )
 66        if name is not UNSET:
 67            field_dict["name"] = name
 68        if description is not UNSET:
 69            field_dict["description"] = description
 70
 71        return field_dict
 72
 73    @classmethod
 74    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 75        from ..models.live_source import LiveSource
 76
 77        d = dict(src_dict)
 78        run_id = d.pop("runId")
 79
 80        sources = []
 81        _sources = d.pop("sources")
 82        for sources_item_data in _sources:
 83            sources_item = LiveSource.from_dict(sources_item_data)
 84
 85            sources.append(sources_item)
 86
 87        state = d.pop("state")
 88
 89        created_at_ms = d.pop("createdAtMs")
 90
 91        name = d.pop("name", UNSET)
 92
 93        description = d.pop("description", UNSET)
 94
 95        public_live_run = cls(
 96            run_id=run_id,
 97            sources=sources,
 98            state=state,
 99            created_at_ms=created_at_ms,
100            name=name,
101            description=description,
102        )
103
104        public_live_run.additional_properties = d
105        return public_live_run
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

A run as it appears in GET /live/public — never reveals who owns it or which strategy it runs.

Attributes: run_id (str): sources (list[LiveSource]): state (str): created_at_ms (int): name (str | Unset): description (str | Unset):

PublicLiveRun( run_id: str, sources: list[LiveSource], state: str, created_at_ms: int, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
29def __init__(self, run_id, sources, state, created_at_ms, name=attr_dict['name'].default, description=attr_dict['description'].default):
30    self.run_id = run_id
31    self.sources = sources
32    self.state = state
33    self.created_at_ms = created_at_ms
34    self.name = name
35    self.description = description
36    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class PublicLiveRun.

run_id: str
sources: list[LiveSource]
state: str
created_at_ms: int
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
40    def to_dict(self) -> dict[str, Any]:
41        run_id = self.run_id
42
43        sources = []
44        for sources_item_data in self.sources:
45            sources_item = sources_item_data.to_dict()
46            sources.append(sources_item)
47
48        state = self.state
49
50        created_at_ms = self.created_at_ms
51
52        name = self.name
53
54        description = self.description
55
56        field_dict: dict[str, Any] = {}
57        field_dict.update(self.additional_properties)
58        field_dict.update(
59            {
60                "runId": run_id,
61                "sources": sources,
62                "state": state,
63                "createdAtMs": created_at_ms,
64            }
65        )
66        if name is not UNSET:
67            field_dict["name"] = name
68        if description is not UNSET:
69            field_dict["description"] = description
70
71        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 73    @classmethod
 74    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 75        from ..models.live_source import LiveSource
 76
 77        d = dict(src_dict)
 78        run_id = d.pop("runId")
 79
 80        sources = []
 81        _sources = d.pop("sources")
 82        for sources_item_data in _sources:
 83            sources_item = LiveSource.from_dict(sources_item_data)
 84
 85            sources.append(sources_item)
 86
 87        state = d.pop("state")
 88
 89        created_at_ms = d.pop("createdAtMs")
 90
 91        name = d.pop("name", UNSET)
 92
 93        description = d.pop("description", UNSET)
 94
 95        public_live_run = cls(
 96            run_id=run_id,
 97            sources=sources,
 98            state=state,
 99            created_at_ms=created_at_ms,
100            name=name,
101            description=description,
102        )
103
104        public_live_run.additional_properties = d
105        return public_live_run
additional_keys: list[str]
107    @property
108    def additional_keys(self) -> list[str]:
109        return list(self.additional_properties.keys())
class ResponseError:
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.

ResponseError(code: int, message: str)
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.

code: int
message: str
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
57    @property
58    def additional_keys(self) -> list[str]:
59        return list(self.additional_properties.keys())
class ResultMap:
 24@_attrs_define
 25class ResultMap:
 26    """Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal,
 27    pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade.
 28    When signal storage is enabled, includes signal fields described below. `notices` carries what the run had to say
 29    about itself, and is absent when it had nothing.
 30
 31        Attributes:
 32            strategy_id (str): **Not the `strategyId` you compiled with** — this is the execution context id,
 33                `strategy:<user>:<strategyId>`. The compiled strategy's id is the last `:`-separated
 34                segment; that, not this whole string, is what `GET /strategy/{strategyId}` takes.
 35
 36                Take the segment after the last `:` rather than counting from the front: the shape has
 37                changed once already and callers that indexed a fixed position broke on it.
 38                 Example: strategy:00000000-0000-0000-0000-000000000000:2iyvtenlzh9dabqtxn7nbv.
 39            instrument (str): The instrument (currency pair) that was backtested Example: BTC/USDT.
 40            host_name (str | Unset): Identifier of the worker that executed the strategy. Useful when reporting issues so
 41                support can correlate with logs. Example: executor10.
 42            iops (float | Unset): Instrument operations per second throughput during execution Example: 123956.53.
 43            notices (list[Notice] | Unset): Diagnostics the engine raised over this run, each with `provenance: execute`.
 44
 45                **Absent means nothing was raised.** This is the one surface where silence is a real
 46                answer: the run happened, over your data, start to finish, and the engine found nothing
 47                worth saying. That is not true of the compile path, where an empty list only means a
 48                short synthetic series reached nothing — see `GET /strategy/{strategyId}`.
 49
 50                Notices are raised on failed and aborted runs too, and those are the ones most worth
 51                reading: a run that produced no trades often did so for a reason stated here.
 52            notices_truncated (int | Unset): How many notices were dropped past the cap of 50. Absent when none were. A
 53                large value usually means one fault repeating per instrument or per parameter vector rather than 50 distinct
 54                problems. Example: 3.
 55            pnl_total (float | Unset): Total profit and loss in the output currency Example: 42.75.
 56            pnl_total_percent (float | Unset): Total PnL as a percentage of the initial capital (`backtestFunding`). Zero
 57                when `backtestFunding` is 0. Example: 42.75.
 58            total_trades (int | Unset): Total number of trades executed by the strategy Example: 156.
 59            win_rate (float | Unset): Fraction of profitable trades, 0.0-1.0 (a rate, not a percent — multiply by 100 to
 60                display as one). Zero when `totalTrades` is 0. Example: 0.5833.
 61            sharpe_ratio (float | Unset): Risk-adjusted return ratio (mean return / standard deviation of returns) Example:
 62                1.245.
 63            sortino_ratio (float | Unset): Downside risk-adjusted return ratio (mean return / downside deviation) Example:
 64                1.872.
 65            cagr (float | Unset): Compound Annual Growth Rate (eg. 0.15 for 15%) Example: 0.1534.
 66            max_drawdown (float | Unset): Maximum absolute drawdown in the output currency Example: 12.5.
 67            max_drawdown_percent (float | Unset): Maximum percentage drawdown from peak equity Example: 8.75.
 68            equity_curve (EquityCurveResult | Unset): An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`,
 69                `timestamps` + `equities` (parallel arrays) when `SHORT`. Used identically wherever a curve is returned — a
 70                plain backtest's inline `equityCurve` and a sweep row's `equityCurve` are the same type. `url` is present
 71                *instead of* any points when the curve is served by pointer rather than inline (a sweep row's top-N winners
 72                only): `GET` it separately to fetch this exact same shape with the points populated.
 73            params (ResultMapParams | Unset): The strategy properties this run was given, echoed back as sent. Absent when
 74                the request carried none, so its presence is what distinguishes a parameterised run from one at the declared
 75                defaults — a stored result cannot otherwise say which vector produced it, and this endpoint is meant to be
 76                called repeatedly over one prepare. Example: {'ema.fast.period': 9, 'ema.slow.period': 21}.
 77            signal_count (int | Unset): Number of signals emitted during strategy execution Example: 100000.
 78            signals_id (str | Unset): Storage key for the signals file. Treat as opaque; use signalsUrl to download.
 79                Example: 00000000-0000-0000-0000-000000000000/exec/binance/3vsndwikcuaatjmb83fjtl.
 80            signals_url (str | Unset): HTTPS URL to download the signals Parquet file. Use signalsUpload to know when it's
 81                ready. Example:
 82                https://storage.qtsurfer.com/00000000-0000-0000-0000-000000000000/exec/binance/3vsndwikcuaatjmb83fjtl.parquet.
 83            signals_upload (ResultMapSignalsUpload | Unset): Upload status. Done = signal file is available at signalsUrl.
 84                Failed = upload error (see signalsUploadReason). Skipped = no signals emitted. Example: Done.
 85            signals_uploaded_at (datetime.datetime | Unset): ISO 8601 timestamp of when the upload completed. Only present
 86                when signalsUpload is Done. Example: 2026-03-18T13:21:48.170Z.
 87            signals_upload_reason (str | Unset): Human-readable reason when signalsUpload is Failed or Skipped. Example:
 88                signal file generation failed.
 89    """
 90
 91    strategy_id: str
 92    instrument: str
 93    host_name: str | Unset = UNSET
 94    iops: float | Unset = UNSET
 95    notices: list[Notice] | Unset = UNSET
 96    notices_truncated: int | Unset = UNSET
 97    pnl_total: float | Unset = UNSET
 98    pnl_total_percent: float | Unset = UNSET
 99    total_trades: int | Unset = UNSET
100    win_rate: float | Unset = UNSET
101    sharpe_ratio: float | Unset = UNSET
102    sortino_ratio: float | Unset = UNSET
103    cagr: float | Unset = UNSET
104    max_drawdown: float | Unset = UNSET
105    max_drawdown_percent: float | Unset = UNSET
106    equity_curve: EquityCurveResult | Unset = UNSET
107    params: ResultMapParams | Unset = UNSET
108    signal_count: int | Unset = UNSET
109    signals_id: str | Unset = UNSET
110    signals_url: str | Unset = UNSET
111    signals_upload: ResultMapSignalsUpload | Unset = UNSET
112    signals_uploaded_at: datetime.datetime | Unset = UNSET
113    signals_upload_reason: str | Unset = UNSET
114    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
115
116    def to_dict(self) -> dict[str, Any]:
117        strategy_id = self.strategy_id
118
119        instrument = self.instrument
120
121        host_name = self.host_name
122
123        iops = self.iops
124
125        notices: list[dict[str, Any]] | Unset = UNSET
126        if not isinstance(self.notices, Unset):
127            notices = []
128            for notices_item_data in self.notices:
129                notices_item = notices_item_data.to_dict()
130                notices.append(notices_item)
131
132        notices_truncated = self.notices_truncated
133
134        pnl_total = self.pnl_total
135
136        pnl_total_percent = self.pnl_total_percent
137
138        total_trades = self.total_trades
139
140        win_rate = self.win_rate
141
142        sharpe_ratio = self.sharpe_ratio
143
144        sortino_ratio = self.sortino_ratio
145
146        cagr = self.cagr
147
148        max_drawdown = self.max_drawdown
149
150        max_drawdown_percent = self.max_drawdown_percent
151
152        equity_curve: dict[str, Any] | Unset = UNSET
153        if not isinstance(self.equity_curve, Unset):
154            equity_curve = self.equity_curve.to_dict()
155
156        params: dict[str, Any] | Unset = UNSET
157        if not isinstance(self.params, Unset):
158            params = self.params.to_dict()
159
160        signal_count = self.signal_count
161
162        signals_id = self.signals_id
163
164        signals_url = self.signals_url
165
166        signals_upload: str | Unset = UNSET
167        if not isinstance(self.signals_upload, Unset):
168            signals_upload = self.signals_upload.value
169
170        signals_uploaded_at: str | Unset = UNSET
171        if not isinstance(self.signals_uploaded_at, Unset):
172            signals_uploaded_at = self.signals_uploaded_at.isoformat()
173
174        signals_upload_reason = self.signals_upload_reason
175
176        field_dict: dict[str, Any] = {}
177        field_dict.update(self.additional_properties)
178        field_dict.update(
179            {
180                "strategyId": strategy_id,
181                "instrument": instrument,
182            }
183        )
184        if host_name is not UNSET:
185            field_dict["hostName"] = host_name
186        if iops is not UNSET:
187            field_dict["iops"] = iops
188        if notices is not UNSET:
189            field_dict["notices"] = notices
190        if notices_truncated is not UNSET:
191            field_dict["noticesTruncated"] = notices_truncated
192        if pnl_total is not UNSET:
193            field_dict["pnlTotal"] = pnl_total
194        if pnl_total_percent is not UNSET:
195            field_dict["pnlTotalPercent"] = pnl_total_percent
196        if total_trades is not UNSET:
197            field_dict["totalTrades"] = total_trades
198        if win_rate is not UNSET:
199            field_dict["winRate"] = win_rate
200        if sharpe_ratio is not UNSET:
201            field_dict["sharpeRatio"] = sharpe_ratio
202        if sortino_ratio is not UNSET:
203            field_dict["sortinoRatio"] = sortino_ratio
204        if cagr is not UNSET:
205            field_dict["cagr"] = cagr
206        if max_drawdown is not UNSET:
207            field_dict["maxDrawdown"] = max_drawdown
208        if max_drawdown_percent is not UNSET:
209            field_dict["maxDrawdownPercent"] = max_drawdown_percent
210        if equity_curve is not UNSET:
211            field_dict["equityCurve"] = equity_curve
212        if params is not UNSET:
213            field_dict["params"] = params
214        if signal_count is not UNSET:
215            field_dict["signalCount"] = signal_count
216        if signals_id is not UNSET:
217            field_dict["signalsId"] = signals_id
218        if signals_url is not UNSET:
219            field_dict["signalsUrl"] = signals_url
220        if signals_upload is not UNSET:
221            field_dict["signalsUpload"] = signals_upload
222        if signals_uploaded_at is not UNSET:
223            field_dict["signalsUploadedAt"] = signals_uploaded_at
224        if signals_upload_reason is not UNSET:
225            field_dict["signalsUploadReason"] = signals_upload_reason
226
227        return field_dict
228
229    @classmethod
230    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
231        from ..models.equity_curve_result import EquityCurveResult
232        from ..models.notice import Notice
233        from ..models.result_map_params import ResultMapParams
234
235        d = dict(src_dict)
236        strategy_id = d.pop("strategyId")
237
238        instrument = d.pop("instrument")
239
240        host_name = d.pop("hostName", UNSET)
241
242        iops = d.pop("iops", UNSET)
243
244        _notices = d.pop("notices", UNSET)
245        notices: list[Notice] | Unset = UNSET
246        if _notices is not UNSET:
247            notices = []
248            for notices_item_data in _notices:
249                notices_item = Notice.from_dict(notices_item_data)
250
251                notices.append(notices_item)
252
253        notices_truncated = d.pop("noticesTruncated", UNSET)
254
255        pnl_total = d.pop("pnlTotal", UNSET)
256
257        pnl_total_percent = d.pop("pnlTotalPercent", UNSET)
258
259        total_trades = d.pop("totalTrades", UNSET)
260
261        win_rate = d.pop("winRate", UNSET)
262
263        sharpe_ratio = d.pop("sharpeRatio", UNSET)
264
265        sortino_ratio = d.pop("sortinoRatio", UNSET)
266
267        cagr = d.pop("cagr", UNSET)
268
269        max_drawdown = d.pop("maxDrawdown", UNSET)
270
271        max_drawdown_percent = d.pop("maxDrawdownPercent", UNSET)
272
273        _equity_curve = d.pop("equityCurve", UNSET)
274        equity_curve: EquityCurveResult | Unset
275        if isinstance(_equity_curve, Unset):
276            equity_curve = UNSET
277        else:
278            equity_curve = EquityCurveResult.from_dict(_equity_curve)
279
280        _params = d.pop("params", UNSET)
281        params: ResultMapParams | Unset
282        if isinstance(_params, Unset):
283            params = UNSET
284        else:
285            params = ResultMapParams.from_dict(_params)
286
287        signal_count = d.pop("signalCount", UNSET)
288
289        signals_id = d.pop("signalsId", UNSET)
290
291        signals_url = d.pop("signalsUrl", UNSET)
292
293        _signals_upload = d.pop("signalsUpload", UNSET)
294        signals_upload: ResultMapSignalsUpload | Unset
295        if isinstance(_signals_upload, Unset):
296            signals_upload = UNSET
297        else:
298            signals_upload = ResultMapSignalsUpload(_signals_upload)
299
300        _signals_uploaded_at = d.pop("signalsUploadedAt", UNSET)
301        signals_uploaded_at: datetime.datetime | Unset
302        if isinstance(_signals_uploaded_at, Unset):
303            signals_uploaded_at = UNSET
304        else:
305            signals_uploaded_at = isoparse(_signals_uploaded_at)
306
307        signals_upload_reason = d.pop("signalsUploadReason", UNSET)
308
309        result_map = cls(
310            strategy_id=strategy_id,
311            instrument=instrument,
312            host_name=host_name,
313            iops=iops,
314            notices=notices,
315            notices_truncated=notices_truncated,
316            pnl_total=pnl_total,
317            pnl_total_percent=pnl_total_percent,
318            total_trades=total_trades,
319            win_rate=win_rate,
320            sharpe_ratio=sharpe_ratio,
321            sortino_ratio=sortino_ratio,
322            cagr=cagr,
323            max_drawdown=max_drawdown,
324            max_drawdown_percent=max_drawdown_percent,
325            equity_curve=equity_curve,
326            params=params,
327            signal_count=signal_count,
328            signals_id=signals_id,
329            signals_url=signals_url,
330            signals_upload=signals_upload,
331            signals_uploaded_at=signals_uploaded_at,
332            signals_upload_reason=signals_upload_reason,
333        )
334
335        result_map.additional_properties = d
336        return result_map
337
338    @property
339    def additional_keys(self) -> list[str]:
340        return list(self.additional_properties.keys())
341
342    def __getitem__(self, key: str) -> Any:
343        return self.additional_properties[key]
344
345    def __setitem__(self, key: str, value: Any) -> None:
346        self.additional_properties[key] = value
347
348    def __delitem__(self, key: str) -> None:
349        del self.additional_properties[key]
350
351    def __contains__(self, key: str) -> bool:
352        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): Fraction of profitable trades, 0.0-1.0 (a rate, not a percent — multiply by 100 to
        display as one). Zero when `totalTrades` is 0. Example: 0.5833.
    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 (eg. 0.15 for 15%) 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.
    params (ResultMapParams | Unset): The strategy properties this run was given, echoed back as sent. Absent when
        the request carried none, so its presence is what distinguishes a parameterised run from one at the declared
        defaults — a stored result cannot otherwise say which vector produced it, and this endpoint is meant to be
        called repeatedly over one prepare. Example: {'ema.fast.period': 9, 'ema.slow.period': 21}.
    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.
ResultMap( strategy_id: str, instrument: str, host_name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, iops: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, notices: list[Notice] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, notices_truncated: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, pnl_total: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, pnl_total_percent: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, total_trades: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, win_rate: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, sharpe_ratio: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, sortino_ratio: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cagr: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, max_drawdown: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, max_drawdown_percent: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, equity_curve: EquityCurveResult | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, params: ResultMapParams | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, signal_count: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, signals_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, signals_url: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, signals_upload: ResultMapSignalsUpload | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, signals_uploaded_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, signals_upload_reason: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
46def __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, params=attr_dict['params'].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):
47    self.strategy_id = strategy_id
48    self.instrument = instrument
49    self.host_name = host_name
50    self.iops = iops
51    self.notices = notices
52    self.notices_truncated = notices_truncated
53    self.pnl_total = pnl_total
54    self.pnl_total_percent = pnl_total_percent
55    self.total_trades = total_trades
56    self.win_rate = win_rate
57    self.sharpe_ratio = sharpe_ratio
58    self.sortino_ratio = sortino_ratio
59    self.cagr = cagr
60    self.max_drawdown = max_drawdown
61    self.max_drawdown_percent = max_drawdown_percent
62    self.equity_curve = equity_curve
63    self.params = params
64    self.signal_count = signal_count
65    self.signals_id = signals_id
66    self.signals_url = signals_url
67    self.signals_upload = signals_upload
68    self.signals_uploaded_at = signals_uploaded_at
69    self.signals_upload_reason = signals_upload_reason
70    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class ResultMap.

strategy_id: str
instrument: str
host_name: str | qtsurfer.api.client._generated.types.Unset
iops: float | qtsurfer.api.client._generated.types.Unset
notices: list[Notice] | qtsurfer.api.client._generated.types.Unset
notices_truncated: int | qtsurfer.api.client._generated.types.Unset
pnl_total: float | qtsurfer.api.client._generated.types.Unset
pnl_total_percent: float | qtsurfer.api.client._generated.types.Unset
total_trades: int | qtsurfer.api.client._generated.types.Unset
win_rate: float | qtsurfer.api.client._generated.types.Unset
sharpe_ratio: float | qtsurfer.api.client._generated.types.Unset
sortino_ratio: float | qtsurfer.api.client._generated.types.Unset
cagr: float | qtsurfer.api.client._generated.types.Unset
max_drawdown: float | qtsurfer.api.client._generated.types.Unset
max_drawdown_percent: float | qtsurfer.api.client._generated.types.Unset
equity_curve: EquityCurveResult | qtsurfer.api.client._generated.types.Unset
params: ResultMapParams | qtsurfer.api.client._generated.types.Unset
signal_count: int | qtsurfer.api.client._generated.types.Unset
signals_id: str | qtsurfer.api.client._generated.types.Unset
signals_url: str | qtsurfer.api.client._generated.types.Unset
signals_upload: ResultMapSignalsUpload | qtsurfer.api.client._generated.types.Unset
signals_uploaded_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
signals_upload_reason: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
116    def to_dict(self) -> dict[str, Any]:
117        strategy_id = self.strategy_id
118
119        instrument = self.instrument
120
121        host_name = self.host_name
122
123        iops = self.iops
124
125        notices: list[dict[str, Any]] | Unset = UNSET
126        if not isinstance(self.notices, Unset):
127            notices = []
128            for notices_item_data in self.notices:
129                notices_item = notices_item_data.to_dict()
130                notices.append(notices_item)
131
132        notices_truncated = self.notices_truncated
133
134        pnl_total = self.pnl_total
135
136        pnl_total_percent = self.pnl_total_percent
137
138        total_trades = self.total_trades
139
140        win_rate = self.win_rate
141
142        sharpe_ratio = self.sharpe_ratio
143
144        sortino_ratio = self.sortino_ratio
145
146        cagr = self.cagr
147
148        max_drawdown = self.max_drawdown
149
150        max_drawdown_percent = self.max_drawdown_percent
151
152        equity_curve: dict[str, Any] | Unset = UNSET
153        if not isinstance(self.equity_curve, Unset):
154            equity_curve = self.equity_curve.to_dict()
155
156        params: dict[str, Any] | Unset = UNSET
157        if not isinstance(self.params, Unset):
158            params = self.params.to_dict()
159
160        signal_count = self.signal_count
161
162        signals_id = self.signals_id
163
164        signals_url = self.signals_url
165
166        signals_upload: str | Unset = UNSET
167        if not isinstance(self.signals_upload, Unset):
168            signals_upload = self.signals_upload.value
169
170        signals_uploaded_at: str | Unset = UNSET
171        if not isinstance(self.signals_uploaded_at, Unset):
172            signals_uploaded_at = self.signals_uploaded_at.isoformat()
173
174        signals_upload_reason = self.signals_upload_reason
175
176        field_dict: dict[str, Any] = {}
177        field_dict.update(self.additional_properties)
178        field_dict.update(
179            {
180                "strategyId": strategy_id,
181                "instrument": instrument,
182            }
183        )
184        if host_name is not UNSET:
185            field_dict["hostName"] = host_name
186        if iops is not UNSET:
187            field_dict["iops"] = iops
188        if notices is not UNSET:
189            field_dict["notices"] = notices
190        if notices_truncated is not UNSET:
191            field_dict["noticesTruncated"] = notices_truncated
192        if pnl_total is not UNSET:
193            field_dict["pnlTotal"] = pnl_total
194        if pnl_total_percent is not UNSET:
195            field_dict["pnlTotalPercent"] = pnl_total_percent
196        if total_trades is not UNSET:
197            field_dict["totalTrades"] = total_trades
198        if win_rate is not UNSET:
199            field_dict["winRate"] = win_rate
200        if sharpe_ratio is not UNSET:
201            field_dict["sharpeRatio"] = sharpe_ratio
202        if sortino_ratio is not UNSET:
203            field_dict["sortinoRatio"] = sortino_ratio
204        if cagr is not UNSET:
205            field_dict["cagr"] = cagr
206        if max_drawdown is not UNSET:
207            field_dict["maxDrawdown"] = max_drawdown
208        if max_drawdown_percent is not UNSET:
209            field_dict["maxDrawdownPercent"] = max_drawdown_percent
210        if equity_curve is not UNSET:
211            field_dict["equityCurve"] = equity_curve
212        if params is not UNSET:
213            field_dict["params"] = params
214        if signal_count is not UNSET:
215            field_dict["signalCount"] = signal_count
216        if signals_id is not UNSET:
217            field_dict["signalsId"] = signals_id
218        if signals_url is not UNSET:
219            field_dict["signalsUrl"] = signals_url
220        if signals_upload is not UNSET:
221            field_dict["signalsUpload"] = signals_upload
222        if signals_uploaded_at is not UNSET:
223            field_dict["signalsUploadedAt"] = signals_uploaded_at
224        if signals_upload_reason is not UNSET:
225            field_dict["signalsUploadReason"] = signals_upload_reason
226
227        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
229    @classmethod
230    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
231        from ..models.equity_curve_result import EquityCurveResult
232        from ..models.notice import Notice
233        from ..models.result_map_params import ResultMapParams
234
235        d = dict(src_dict)
236        strategy_id = d.pop("strategyId")
237
238        instrument = d.pop("instrument")
239
240        host_name = d.pop("hostName", UNSET)
241
242        iops = d.pop("iops", UNSET)
243
244        _notices = d.pop("notices", UNSET)
245        notices: list[Notice] | Unset = UNSET
246        if _notices is not UNSET:
247            notices = []
248            for notices_item_data in _notices:
249                notices_item = Notice.from_dict(notices_item_data)
250
251                notices.append(notices_item)
252
253        notices_truncated = d.pop("noticesTruncated", UNSET)
254
255        pnl_total = d.pop("pnlTotal", UNSET)
256
257        pnl_total_percent = d.pop("pnlTotalPercent", UNSET)
258
259        total_trades = d.pop("totalTrades", UNSET)
260
261        win_rate = d.pop("winRate", UNSET)
262
263        sharpe_ratio = d.pop("sharpeRatio", UNSET)
264
265        sortino_ratio = d.pop("sortinoRatio", UNSET)
266
267        cagr = d.pop("cagr", UNSET)
268
269        max_drawdown = d.pop("maxDrawdown", UNSET)
270
271        max_drawdown_percent = d.pop("maxDrawdownPercent", UNSET)
272
273        _equity_curve = d.pop("equityCurve", UNSET)
274        equity_curve: EquityCurveResult | Unset
275        if isinstance(_equity_curve, Unset):
276            equity_curve = UNSET
277        else:
278            equity_curve = EquityCurveResult.from_dict(_equity_curve)
279
280        _params = d.pop("params", UNSET)
281        params: ResultMapParams | Unset
282        if isinstance(_params, Unset):
283            params = UNSET
284        else:
285            params = ResultMapParams.from_dict(_params)
286
287        signal_count = d.pop("signalCount", UNSET)
288
289        signals_id = d.pop("signalsId", UNSET)
290
291        signals_url = d.pop("signalsUrl", UNSET)
292
293        _signals_upload = d.pop("signalsUpload", UNSET)
294        signals_upload: ResultMapSignalsUpload | Unset
295        if isinstance(_signals_upload, Unset):
296            signals_upload = UNSET
297        else:
298            signals_upload = ResultMapSignalsUpload(_signals_upload)
299
300        _signals_uploaded_at = d.pop("signalsUploadedAt", UNSET)
301        signals_uploaded_at: datetime.datetime | Unset
302        if isinstance(_signals_uploaded_at, Unset):
303            signals_uploaded_at = UNSET
304        else:
305            signals_uploaded_at = isoparse(_signals_uploaded_at)
306
307        signals_upload_reason = d.pop("signalsUploadReason", UNSET)
308
309        result_map = cls(
310            strategy_id=strategy_id,
311            instrument=instrument,
312            host_name=host_name,
313            iops=iops,
314            notices=notices,
315            notices_truncated=notices_truncated,
316            pnl_total=pnl_total,
317            pnl_total_percent=pnl_total_percent,
318            total_trades=total_trades,
319            win_rate=win_rate,
320            sharpe_ratio=sharpe_ratio,
321            sortino_ratio=sortino_ratio,
322            cagr=cagr,
323            max_drawdown=max_drawdown,
324            max_drawdown_percent=max_drawdown_percent,
325            equity_curve=equity_curve,
326            params=params,
327            signal_count=signal_count,
328            signals_id=signals_id,
329            signals_url=signals_url,
330            signals_upload=signals_upload,
331            signals_uploaded_at=signals_uploaded_at,
332            signals_upload_reason=signals_upload_reason,
333        )
334
335        result_map.additional_properties = d
336        return result_map
additional_keys: list[str]
338    @property
339    def additional_keys(self) -> list[str]:
340        return list(self.additional_properties.keys())
class ResultMapParams:
13@_attrs_define
14class ResultMapParams:
15    """The strategy properties this run was given, echoed back as sent. Absent when the request carried none, so its
16    presence is what distinguishes a parameterised run from one at the declared defaults — a stored result cannot
17    otherwise say which vector produced it, and this endpoint is meant to be called repeatedly over one prepare.
18
19        Example:
20            {'ema.fast.period': 9, 'ema.slow.period': 21}
21
22    """
23
24    additional_properties: dict[str, bool | float | str] = _attrs_field(init=False, factory=dict)
25
26    def to_dict(self) -> dict[str, Any]:
27
28        field_dict: dict[str, Any] = {}
29        for prop_name, prop in self.additional_properties.items():
30            field_dict[prop_name] = prop
31
32        return field_dict
33
34    @classmethod
35    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
36        d = dict(src_dict)
37        result_map_params = cls()
38
39        additional_properties = {}
40        for prop_name, prop_dict in d.items():
41
42            def _parse_additional_property(data: object) -> bool | float | str:
43                return cast(bool | float | str, data)
44
45            additional_property = _parse_additional_property(prop_dict)
46
47            additional_properties[prop_name] = additional_property
48
49        result_map_params.additional_properties = additional_properties
50        return result_map_params
51
52    @property
53    def additional_keys(self) -> list[str]:
54        return list(self.additional_properties.keys())
55
56    def __getitem__(self, key: str) -> bool | float | str:
57        return self.additional_properties[key]
58
59    def __setitem__(self, key: str, value: bool | float | str) -> None:
60        self.additional_properties[key] = value
61
62    def __delitem__(self, key: str) -> None:
63        del self.additional_properties[key]
64
65    def __contains__(self, key: str) -> bool:
66        return key in self.additional_properties

The strategy properties this run was given, echoed back as sent. Absent when the request carried none, so its presence is what distinguishes a parameterised run from one at the declared defaults — a stored result cannot otherwise say which vector produced it, and this endpoint is meant to be called repeatedly over one prepare.

Example:
    {'ema.fast.period': 9, 'ema.slow.period': 21}
ResultMapParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class ResultMapParams.

additional_properties: dict[str, bool | float | str]
def to_dict(self) -> dict[str, typing.Any]:
26    def to_dict(self) -> dict[str, Any]:
27
28        field_dict: dict[str, Any] = {}
29        for prop_name, prop in self.additional_properties.items():
30            field_dict[prop_name] = prop
31
32        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
34    @classmethod
35    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
36        d = dict(src_dict)
37        result_map_params = cls()
38
39        additional_properties = {}
40        for prop_name, prop_dict in d.items():
41
42            def _parse_additional_property(data: object) -> bool | float | str:
43                return cast(bool | float | str, data)
44
45            additional_property = _parse_additional_property(prop_dict)
46
47            additional_properties[prop_name] = additional_property
48
49        result_map_params.additional_properties = additional_properties
50        return result_map_params
additional_keys: list[str]
52    @property
53    def additional_keys(self) -> list[str]:
54        return list(self.additional_properties.keys())
class ResultMapSignalsUpload(builtins.str, enum.Enum):
 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'.

DONE = <ResultMapSignalsUpload.DONE: 'Done'>
FAILED = <ResultMapSignalsUpload.FAILED: 'Failed'>
SKIPPED = <ResultMapSignalsUpload.SKIPPED: 'Skipped'>
class SendLiveCommandRequest:
19@_attrs_define
20class SendLiveCommandRequest:
21    """
22    Attributes:
23        command (str): The command's text — non-blank.
24        properties (SendLiveCommandRequestProperties | Unset): An optional map of your own choosing, alongside command.
25            Absent means none; when given, it must be a JSON object, and `command` and `properties` are the only keys the
26            body may carry. Each entry lands as a top-level entry on the strategy's `CommandRequest` — no key is off limits,
27            since the command's own text is kept separately.
28    """
29
30    command: str
31    properties: SendLiveCommandRequestProperties | Unset = UNSET
32    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
33
34    def to_dict(self) -> dict[str, Any]:
35        command = self.command
36
37        properties: dict[str, Any] | Unset = UNSET
38        if not isinstance(self.properties, Unset):
39            properties = self.properties.to_dict()
40
41        field_dict: dict[str, Any] = {}
42        field_dict.update(self.additional_properties)
43        field_dict.update(
44            {
45                "command": command,
46            }
47        )
48        if properties is not UNSET:
49            field_dict["properties"] = properties
50
51        return field_dict
52
53    @classmethod
54    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
55        from ..models.send_live_command_request_properties import SendLiveCommandRequestProperties
56
57        d = dict(src_dict)
58        command = d.pop("command")
59
60        _properties = d.pop("properties", UNSET)
61        properties: SendLiveCommandRequestProperties | Unset
62        if isinstance(_properties, Unset):
63            properties = UNSET
64        else:
65            properties = SendLiveCommandRequestProperties.from_dict(_properties)
66
67        send_live_command_request = cls(
68            command=command,
69            properties=properties,
70        )
71
72        send_live_command_request.additional_properties = d
73        return send_live_command_request
74
75    @property
76    def additional_keys(self) -> list[str]:
77        return list(self.additional_properties.keys())
78
79    def __getitem__(self, key: str) -> Any:
80        return self.additional_properties[key]
81
82    def __setitem__(self, key: str, value: Any) -> None:
83        self.additional_properties[key] = value
84
85    def __delitem__(self, key: str) -> None:
86        del self.additional_properties[key]
87
88    def __contains__(self, key: str) -> bool:
89        return key in self.additional_properties

Attributes: command (str): The command's text — non-blank. properties (SendLiveCommandRequestProperties | Unset): An optional map of your own choosing, alongside command. Absent means none; when given, it must be a JSON object, and command and properties are the only keys the body may carry. Each entry lands as a top-level entry on the strategy's CommandRequest — no key is off limits, since the command's own text is kept separately.

SendLiveCommandRequest( command: str, properties: SendLiveCommandRequestProperties | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
25def __init__(self, command, properties=attr_dict['properties'].default):
26    self.command = command
27    self.properties = properties
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class SendLiveCommandRequest.

command: str
properties: SendLiveCommandRequestProperties | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
34    def to_dict(self) -> dict[str, Any]:
35        command = self.command
36
37        properties: dict[str, Any] | Unset = UNSET
38        if not isinstance(self.properties, Unset):
39            properties = self.properties.to_dict()
40
41        field_dict: dict[str, Any] = {}
42        field_dict.update(self.additional_properties)
43        field_dict.update(
44            {
45                "command": command,
46            }
47        )
48        if properties is not UNSET:
49            field_dict["properties"] = properties
50
51        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
53    @classmethod
54    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
55        from ..models.send_live_command_request_properties import SendLiveCommandRequestProperties
56
57        d = dict(src_dict)
58        command = d.pop("command")
59
60        _properties = d.pop("properties", UNSET)
61        properties: SendLiveCommandRequestProperties | Unset
62        if isinstance(_properties, Unset):
63            properties = UNSET
64        else:
65            properties = SendLiveCommandRequestProperties.from_dict(_properties)
66
67        send_live_command_request = cls(
68            command=command,
69            properties=properties,
70        )
71
72        send_live_command_request.additional_properties = d
73        return send_live_command_request
additional_keys: list[str]
75    @property
76    def additional_keys(self) -> list[str]:
77        return list(self.additional_properties.keys())
class SendLiveCommandRequestProperties:
13@_attrs_define
14class SendLiveCommandRequestProperties:
15    """An optional map of your own choosing, alongside command. Absent means none; when given, it must be a JSON object,
16    and `command` and `properties` are the only keys the body may carry. Each entry lands as a top-level entry on the
17    strategy's `CommandRequest` — no key is off limits, since the command's own text is kept separately.
18
19    """
20
21    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
22
23    def to_dict(self) -> dict[str, Any]:
24
25        field_dict: dict[str, Any] = {}
26        field_dict.update(self.additional_properties)
27
28        return field_dict
29
30    @classmethod
31    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
32        d = dict(src_dict)
33        send_live_command_request_properties = cls()
34
35        send_live_command_request_properties.additional_properties = d
36        return send_live_command_request_properties
37
38    @property
39    def additional_keys(self) -> list[str]:
40        return list(self.additional_properties.keys())
41
42    def __getitem__(self, key: str) -> Any:
43        return self.additional_properties[key]
44
45    def __setitem__(self, key: str, value: Any) -> None:
46        self.additional_properties[key] = value
47
48    def __delitem__(self, key: str) -> None:
49        del self.additional_properties[key]
50
51    def __contains__(self, key: str) -> bool:
52        return key in self.additional_properties

An optional map of your own choosing, alongside command. Absent means none; when given, it must be a JSON object, and command and properties are the only keys the body may carry. Each entry lands as a top-level entry on the strategy's CommandRequest — no key is off limits, since the command's own text is kept separately.

SendLiveCommandRequestProperties()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class SendLiveCommandRequestProperties.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
23    def to_dict(self) -> dict[str, Any]:
24
25        field_dict: dict[str, Any] = {}
26        field_dict.update(self.additional_properties)
27
28        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
30    @classmethod
31    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
32        d = dict(src_dict)
33        send_live_command_request_properties = cls()
34
35        send_live_command_request_properties.additional_properties = d
36        return send_live_command_request_properties
additional_keys: list[str]
38    @property
39    def additional_keys(self) -> list[str]:
40        return list(self.additional_properties.keys())
class StartLiveRequest:
 22@_attrs_define
 23class StartLiveRequest:
 24    """
 25    Attributes:
 26        sources (list[LiveSourceRequest]):
 27        params (StartLiveRequestParams | Unset): Strategy parameters to start with. Opaque key/value pairs — see this
 28            strategy's own `declaredProperties` (from `POST /strategy`) for the keys it accepts.
 29        visibility (StartLiveRequestVisibility | Unset): A `public` run appears in `GET /live/public` and its signal
 30            channel accepts subscriptions from anyone, not only you — from the moment it is in the `live` stage, which is
 31            when it is promoted or, for a run that starts there, at once. While it is a `sandbox` trial, `public` is only
 32            what you asked for, and only you can read it. Default: StartLiveRequestVisibility.PRIVATE.
 33        relay (bool | Unset): Request that this run's signals be relayed over its WebSocket channel, from its first
 34            signal — in the `sandbox` stage too, where only you can subscribe to it. See the "Live execution" guide.
 35            Default: False.
 36        sandbox (bool | Unset): Start in the `sandbox` stage even though an earlier run of yours already took this
 37            compiled strategy
 38            through it. Without it, such a strategy starts in `LIVE` at once; with `true` it starts in `SANDBOX` like
 39            a first run, which is how to read its signals back over the connection (`history`, kept for the
 40            `sandbox` stage only) while you debug it. For a strategy that has not been through the sandbox it
 41            changes nothing: it always starts there. Anything other than `true` or `false` is `400`.
 42             Default: False.
 43        stream (bool | Unset): Ask for a **stream URL**: a secret address that a simple client, or a service that passes
 44            your signals
 45            on to others, can open as a plain WebSocket to receive this run's signals as they are produced, one JSON
 46            text frame per signal, with none of the live-execution protocol around it. The URL comes back as
 47            `streamUrl` in the response to this call. Available from the `sandbox` stage on, on the plans that may
 48            broadcast; any other plan gets `429`. It can be asked for **only when the run is started** (not added
 49            later), and it also turns `relay` on. See the "Live execution" guide, "A plain WebSocket stream of a run".
 50             Default: False.
 51        warm_from (int | Unset): How many seconds before the run's start to replay the market feed from, so the
 52            strategy's indicators and
 53            windows have history when its first live tick arrives. `0` replays nothing: the run delivers its first
 54            signal as soon as it is running, but its indicators start empty and the first bar of a window can be
 55            partial. Omitted, the platform replays from the start of the current 15-minute block: between 0 and 900
 56            seconds before the run's start, depending on when it starts (0 if it starts exactly on a quarter hour),
 57            so the first bar of a 15-minute window is complete. The value in effect, the one you sent or the one the
 58            platform chose, is reported back as `warmFrom` on the run. Signals about the replayed time
 59            are not pushed on the run's channel or stream: they describe events from before the run started.
 60            It can be set **only when the run is started**: it is not a parameter of `PUT /live/{runId}/params`, and
 61            changing it means stopping the run and starting it again. Anything that is not an integer from 0 to 3600
 62            is `400`. See the "Live execution" guide, "Warming up".
 63        name (str | Unset):
 64        description (str | Unset):
 65        paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's `baseConfig`
 66            (same fields,
 67            defaults and limits), plus `output`. An empty object takes every default. Each quote
 68            currency the run trades gets its own simulated account, opened with `initialFunding` in
 69            that currency; accounts are never added together. As returned on a run, the block is
 70            normalised: `feeRate` is resolved into `buyFeeRate`/`sellFeeRate` and defaults are filled
 71            in.
 72    """
 73
 74    sources: list[LiveSourceRequest]
 75    params: StartLiveRequestParams | Unset = UNSET
 76    visibility: StartLiveRequestVisibility | Unset = StartLiveRequestVisibility.PRIVATE
 77    relay: bool | Unset = False
 78    sandbox: bool | Unset = False
 79    stream: bool | Unset = False
 80    warm_from: int | Unset = UNSET
 81    name: str | Unset = UNSET
 82    description: str | Unset = UNSET
 83    paper: LivePaperConfig | Unset = UNSET
 84    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 85
 86    def to_dict(self) -> dict[str, Any]:
 87        sources = []
 88        for sources_item_data in self.sources:
 89            sources_item = sources_item_data.to_dict()
 90            sources.append(sources_item)
 91
 92        params: dict[str, Any] | Unset = UNSET
 93        if not isinstance(self.params, Unset):
 94            params = self.params.to_dict()
 95
 96        visibility: str | Unset = UNSET
 97        if not isinstance(self.visibility, Unset):
 98            visibility = self.visibility.value
 99
100        relay = self.relay
101
102        sandbox = self.sandbox
103
104        stream = self.stream
105
106        warm_from = self.warm_from
107
108        name = self.name
109
110        description = self.description
111
112        paper: dict[str, Any] | Unset = UNSET
113        if not isinstance(self.paper, Unset):
114            paper = self.paper.to_dict()
115
116        field_dict: dict[str, Any] = {}
117        field_dict.update(self.additional_properties)
118        field_dict.update(
119            {
120                "sources": sources,
121            }
122        )
123        if params is not UNSET:
124            field_dict["params"] = params
125        if visibility is not UNSET:
126            field_dict["visibility"] = visibility
127        if relay is not UNSET:
128            field_dict["relay"] = relay
129        if sandbox is not UNSET:
130            field_dict["sandbox"] = sandbox
131        if stream is not UNSET:
132            field_dict["stream"] = stream
133        if warm_from is not UNSET:
134            field_dict["warmFrom"] = warm_from
135        if name is not UNSET:
136            field_dict["name"] = name
137        if description is not UNSET:
138            field_dict["description"] = description
139        if paper is not UNSET:
140            field_dict["paper"] = paper
141
142        return field_dict
143
144    @classmethod
145    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
146        from ..models.live_paper_config import LivePaperConfig
147        from ..models.live_source_request import LiveSourceRequest
148        from ..models.start_live_request_params import StartLiveRequestParams
149
150        d = dict(src_dict)
151        sources = []
152        _sources = d.pop("sources")
153        for sources_item_data in _sources:
154            sources_item = LiveSourceRequest.from_dict(sources_item_data)
155
156            sources.append(sources_item)
157
158        _params = d.pop("params", UNSET)
159        params: StartLiveRequestParams | Unset
160        if isinstance(_params, Unset):
161            params = UNSET
162        else:
163            params = StartLiveRequestParams.from_dict(_params)
164
165        _visibility = d.pop("visibility", UNSET)
166        visibility: StartLiveRequestVisibility | Unset
167        if isinstance(_visibility, Unset):
168            visibility = UNSET
169        else:
170            visibility = StartLiveRequestVisibility(_visibility)
171
172        relay = d.pop("relay", UNSET)
173
174        sandbox = d.pop("sandbox", UNSET)
175
176        stream = d.pop("stream", UNSET)
177
178        warm_from = d.pop("warmFrom", UNSET)
179
180        name = d.pop("name", UNSET)
181
182        description = d.pop("description", UNSET)
183
184        _paper = d.pop("paper", UNSET)
185        paper: LivePaperConfig | Unset
186        if isinstance(_paper, Unset):
187            paper = UNSET
188        else:
189            paper = LivePaperConfig.from_dict(_paper)
190
191        start_live_request = cls(
192            sources=sources,
193            params=params,
194            visibility=visibility,
195            relay=relay,
196            sandbox=sandbox,
197            stream=stream,
198            warm_from=warm_from,
199            name=name,
200            description=description,
201            paper=paper,
202        )
203
204        start_live_request.additional_properties = d
205        return start_live_request
206
207    @property
208    def additional_keys(self) -> list[str]:
209        return list(self.additional_properties.keys())
210
211    def __getitem__(self, key: str) -> Any:
212        return self.additional_properties[key]
213
214    def __setitem__(self, key: str, value: Any) -> None:
215        self.additional_properties[key] = value
216
217    def __delitem__(self, key: str) -> None:
218        del self.additional_properties[key]
219
220    def __contains__(self, key: str) -> bool:
221        return key in self.additional_properties

Attributes: sources (list[LiveSourceRequest]): params (StartLiveRequestParams | Unset): Strategy parameters to start with. Opaque key/value pairs — see this strategy's own declaredProperties (from POST /strategy) for the keys it accepts. visibility (StartLiveRequestVisibility | Unset): A public run appears in GET /live/public and its signal channel accepts subscriptions from anyone, not only you — from the moment it is in the live stage, which is when it is promoted or, for a run that starts there, at once. While it is a sandbox trial, public is only what you asked for, and only you can read it. Default: StartLiveRequestVisibility.PRIVATE. relay (bool | Unset): Request that this run's signals be relayed over its WebSocket channel, from its first signal — in the sandbox stage too, where only you can subscribe to it. See the "Live execution" guide. Default: False. sandbox (bool | Unset): Start in the sandbox stage even though an earlier run of yours already took this compiled strategy through it. Without it, such a strategy starts in LIVE at once; with true it starts in SANDBOX like a first run, which is how to read its signals back over the connection (history, kept for the sandbox stage only) while you debug it. For a strategy that has not been through the sandbox it changes nothing: it always starts there. Anything other than true or false is 400. Default: False. stream (bool | Unset): Ask for a stream URL: a secret address that a simple client, or a service that passes your signals on to others, can open as a plain WebSocket to receive this run's signals as they are produced, one JSON text frame per signal, with none of the live-execution protocol around it. The URL comes back as streamUrl in the response to this call. Available from the sandbox stage on, on the plans that may broadcast; any other plan gets 429. It can be asked for only when the run is started (not added later), and it also turns relay on. See the "Live execution" guide, "A plain WebSocket stream of a run". Default: False. warm_from (int | Unset): How many seconds before the run's start to replay the market feed from, so the strategy's indicators and windows have history when its first live tick arrives. 0 replays nothing: the run delivers its first signal as soon as it is running, but its indicators start empty and the first bar of a window can be partial. Omitted, the platform replays from the start of the current 15-minute block: between 0 and 900 seconds before the run's start, depending on when it starts (0 if it starts exactly on a quarter hour), so the first bar of a 15-minute window is complete. The value in effect, the one you sent or the one the platform chose, is reported back as warmFrom on the run. Signals about the replayed time are not pushed on the run's channel or stream: they describe events from before the run started. It can be set only when the run is started: it is not a parameter of PUT /live/{runId}/params, and changing it means stopping the run and starting it again. Anything that is not an integer from 0 to 3600 is 400. See the "Live execution" guide, "Warming up". name (str | Unset): description (str | Unset): paper (LivePaperConfig | Unset): Paper trading for this run: the same economics as a backtest's baseConfig (same fields, defaults and limits), plus output. An empty object takes every default. Each quote currency the run trades gets its own simulated account, opened with initialFunding in that currency; accounts are never added together. As returned on a run, the block is normalised: feeRate is resolved into buyFeeRate/sellFeeRate and defaults are filled in.

StartLiveRequest( sources: list[LiveSourceRequest], params: StartLiveRequestParams | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, visibility: StartLiveRequestVisibility | qtsurfer.api.client._generated.types.Unset = <StartLiveRequestVisibility.PRIVATE: 'private'>, relay: bool | qtsurfer.api.client._generated.types.Unset = False, sandbox: bool | qtsurfer.api.client._generated.types.Unset = False, stream: bool | qtsurfer.api.client._generated.types.Unset = False, warm_from: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
33def __init__(self, sources, params=attr_dict['params'].default, visibility=attr_dict['visibility'].default, relay=attr_dict['relay'].default, sandbox=attr_dict['sandbox'].default, stream=attr_dict['stream'].default, warm_from=attr_dict['warm_from'].default, name=attr_dict['name'].default, description=attr_dict['description'].default, paper=attr_dict['paper'].default):
34    self.sources = sources
35    self.params = params
36    self.visibility = visibility
37    self.relay = relay
38    self.sandbox = sandbox
39    self.stream = stream
40    self.warm_from = warm_from
41    self.name = name
42    self.description = description
43    self.paper = paper
44    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class StartLiveRequest.

sources: list[LiveSourceRequest]
params: StartLiveRequestParams | qtsurfer.api.client._generated.types.Unset
visibility: StartLiveRequestVisibility | qtsurfer.api.client._generated.types.Unset
relay: bool | qtsurfer.api.client._generated.types.Unset
sandbox: bool | qtsurfer.api.client._generated.types.Unset
stream: bool | qtsurfer.api.client._generated.types.Unset
warm_from: int | qtsurfer.api.client._generated.types.Unset
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
paper: LivePaperConfig | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 86    def to_dict(self) -> dict[str, Any]:
 87        sources = []
 88        for sources_item_data in self.sources:
 89            sources_item = sources_item_data.to_dict()
 90            sources.append(sources_item)
 91
 92        params: dict[str, Any] | Unset = UNSET
 93        if not isinstance(self.params, Unset):
 94            params = self.params.to_dict()
 95
 96        visibility: str | Unset = UNSET
 97        if not isinstance(self.visibility, Unset):
 98            visibility = self.visibility.value
 99
100        relay = self.relay
101
102        sandbox = self.sandbox
103
104        stream = self.stream
105
106        warm_from = self.warm_from
107
108        name = self.name
109
110        description = self.description
111
112        paper: dict[str, Any] | Unset = UNSET
113        if not isinstance(self.paper, Unset):
114            paper = self.paper.to_dict()
115
116        field_dict: dict[str, Any] = {}
117        field_dict.update(self.additional_properties)
118        field_dict.update(
119            {
120                "sources": sources,
121            }
122        )
123        if params is not UNSET:
124            field_dict["params"] = params
125        if visibility is not UNSET:
126            field_dict["visibility"] = visibility
127        if relay is not UNSET:
128            field_dict["relay"] = relay
129        if sandbox is not UNSET:
130            field_dict["sandbox"] = sandbox
131        if stream is not UNSET:
132            field_dict["stream"] = stream
133        if warm_from is not UNSET:
134            field_dict["warmFrom"] = warm_from
135        if name is not UNSET:
136            field_dict["name"] = name
137        if description is not UNSET:
138            field_dict["description"] = description
139        if paper is not UNSET:
140            field_dict["paper"] = paper
141
142        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
144    @classmethod
145    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
146        from ..models.live_paper_config import LivePaperConfig
147        from ..models.live_source_request import LiveSourceRequest
148        from ..models.start_live_request_params import StartLiveRequestParams
149
150        d = dict(src_dict)
151        sources = []
152        _sources = d.pop("sources")
153        for sources_item_data in _sources:
154            sources_item = LiveSourceRequest.from_dict(sources_item_data)
155
156            sources.append(sources_item)
157
158        _params = d.pop("params", UNSET)
159        params: StartLiveRequestParams | Unset
160        if isinstance(_params, Unset):
161            params = UNSET
162        else:
163            params = StartLiveRequestParams.from_dict(_params)
164
165        _visibility = d.pop("visibility", UNSET)
166        visibility: StartLiveRequestVisibility | Unset
167        if isinstance(_visibility, Unset):
168            visibility = UNSET
169        else:
170            visibility = StartLiveRequestVisibility(_visibility)
171
172        relay = d.pop("relay", UNSET)
173
174        sandbox = d.pop("sandbox", UNSET)
175
176        stream = d.pop("stream", UNSET)
177
178        warm_from = d.pop("warmFrom", UNSET)
179
180        name = d.pop("name", UNSET)
181
182        description = d.pop("description", UNSET)
183
184        _paper = d.pop("paper", UNSET)
185        paper: LivePaperConfig | Unset
186        if isinstance(_paper, Unset):
187            paper = UNSET
188        else:
189            paper = LivePaperConfig.from_dict(_paper)
190
191        start_live_request = cls(
192            sources=sources,
193            params=params,
194            visibility=visibility,
195            relay=relay,
196            sandbox=sandbox,
197            stream=stream,
198            warm_from=warm_from,
199            name=name,
200            description=description,
201            paper=paper,
202        )
203
204        start_live_request.additional_properties = d
205        return start_live_request
additional_keys: list[str]
207    @property
208    def additional_keys(self) -> list[str]:
209        return list(self.additional_properties.keys())
class StartLiveRequestParams:
13@_attrs_define
14class StartLiveRequestParams:
15    """Strategy parameters to start with. Opaque key/value pairs — see this strategy's own `declaredProperties` (from `POST
16    /strategy`) for the keys it accepts.
17
18    """
19
20    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
21
22    def to_dict(self) -> dict[str, Any]:
23
24        field_dict: dict[str, Any] = {}
25        field_dict.update(self.additional_properties)
26
27        return field_dict
28
29    @classmethod
30    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
31        d = dict(src_dict)
32        start_live_request_params = cls()
33
34        start_live_request_params.additional_properties = d
35        return start_live_request_params
36
37    @property
38    def additional_keys(self) -> list[str]:
39        return list(self.additional_properties.keys())
40
41    def __getitem__(self, key: str) -> Any:
42        return self.additional_properties[key]
43
44    def __setitem__(self, key: str, value: Any) -> None:
45        self.additional_properties[key] = value
46
47    def __delitem__(self, key: str) -> None:
48        del self.additional_properties[key]
49
50    def __contains__(self, key: str) -> bool:
51        return key in self.additional_properties

Strategy parameters to start with. Opaque key/value pairs — see this strategy's own declaredProperties (from POST /strategy) for the keys it accepts.

StartLiveRequestParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class StartLiveRequestParams.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
22    def to_dict(self) -> dict[str, Any]:
23
24        field_dict: dict[str, Any] = {}
25        field_dict.update(self.additional_properties)
26
27        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
29    @classmethod
30    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
31        d = dict(src_dict)
32        start_live_request_params = cls()
33
34        start_live_request_params.additional_properties = d
35        return start_live_request_params
additional_keys: list[str]
37    @property
38    def additional_keys(self) -> list[str]:
39        return list(self.additional_properties.keys())
class StartLiveRequestVisibility(builtins.str, enum.Enum):
 5class StartLiveRequestVisibility(str, Enum):
 6    PRIVATE = "private"
 7    PUBLIC = "public"
 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'.

PRIVATE = <StartLiveRequestVisibility.PRIVATE: 'private'>
PUBLIC = <StartLiveRequestVisibility.PUBLIC: 'public'>
class StrategyState:
 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. How much formatting the id ignores depends on
 41                the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 42                not.
 43                 Example: 6bsh31ikwkuivhtgcoa6s4.
 44            validation (StrategyStateValidation): * `not_validated` — registered, never checked. `POST
 45                /strategy/{strategyId}/validate`
 46                  checks it.
 47                * `pending` — a check was asked for and has not answered yet.
 48                * `passed` — the class loaded and survived its first event.
 49                * `failed` — it did not; `detail` says how.
 50                 Example: passed.
 51            compiled_at (datetime.datetime | Unset): When the live compilation was produced.
 52            required_sources (list[StrategyStateRequiredSourcesItem] | Unset): The market data a strategy needs, read off
 53                the compiled class rather than off anything
 54                you sent — `TickerStrategy`, `KlineStrategy` and `FundingRateStrategy` each declare one,
 55                and a `MultiSourceStrategy` declares a set.
 56
 57                **Absent is not "needs nothing".** A strategy always needs market data, so an absent
 58                field never means an empty requirement — it means the platform could not establish the
 59                answer without constructing your strategy, which it will not do to fill in a field.
 60                That happens for a `MultiSourceStrategy`, for a class that overrides
 61                `getMarketDataSource()`, and for anything registered before this field existed;
 62                re-registering the source fills it in.
 63                 Example: ['Ticker'].
 64            validated_at (datetime.datetime | Unset): When the verdict was recorded. Absent until there is one.
 65            detail (str | Unset): Why validation failed, or why a queued check has not reported. Present on `failed`, and
 66                alongside `validationStalled`.
 67            notices (list[Notice] | Unset): What the run surfaced. An empty or absent list is not a clean bill of health
 68                when
 69                `dryRunIncomplete` is true — see that field.
 70            notices_truncated (int | Unset): How many notices were dropped past the cap. Absent when none were. Example: 3.
 71            dry_run_incomplete (bool | Unset): The check did not finish its budget — it ran out of time, was refused because
 72                the
 73                platform was already holding too many unfinishable runs, or hit a failure attributable to
 74                the synthetic instrument rather than to your strategy. The verdict stands as far as it
 75                went; it simply reached less than a full run would.
 76            validation_stalled (bool | Unset): A queued check has not reported for far longer than one takes. Nothing is
 77                disproved about
 78                the strategy — the check has not run. Stop waiting and re-request it later.
 79            field_links (StrategyLinks | Unset): HAL `_links` for a strategy — present on a full `StrategyState` body (`GET
 80                /strategy/{strategyId}`, and `POST /strategy/{strategyId}/validate`'s already-validated
 81                `200`), absent from that same endpoint's `202` — a deliberately partial stub carrying only
 82                what is known before a check has even started. Following `code` can still `404` once
 83                present: it documents its own honest "nothing to return" for a strategy with no source of
 84                its own (a `REFERENCE` marketplace copy, or one resolved only through the platform's shared
 85                pool). This link says where to look, not that something is there.
 86    """
 87
 88    strategy_id: str
 89    validation: StrategyStateValidation
 90    compiled_at: datetime.datetime | Unset = UNSET
 91    required_sources: list[StrategyStateRequiredSourcesItem] | Unset = UNSET
 92    validated_at: datetime.datetime | Unset = UNSET
 93    detail: str | Unset = UNSET
 94    notices: list[Notice] | Unset = UNSET
 95    notices_truncated: int | Unset = UNSET
 96    dry_run_incomplete: bool | Unset = UNSET
 97    validation_stalled: bool | Unset = UNSET
 98    field_links: StrategyLinks | Unset = UNSET
 99    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
100
101    def to_dict(self) -> dict[str, Any]:
102        strategy_id = self.strategy_id
103
104        validation = self.validation.value
105
106        compiled_at: str | Unset = UNSET
107        if not isinstance(self.compiled_at, Unset):
108            compiled_at = self.compiled_at.isoformat()
109
110        required_sources: list[str] | Unset = UNSET
111        if not isinstance(self.required_sources, Unset):
112            required_sources = []
113            for required_sources_item_data in self.required_sources:
114                required_sources_item = required_sources_item_data.value
115                required_sources.append(required_sources_item)
116
117        validated_at: str | Unset = UNSET
118        if not isinstance(self.validated_at, Unset):
119            validated_at = self.validated_at.isoformat()
120
121        detail = self.detail
122
123        notices: list[dict[str, Any]] | Unset = UNSET
124        if not isinstance(self.notices, Unset):
125            notices = []
126            for notices_item_data in self.notices:
127                notices_item = notices_item_data.to_dict()
128                notices.append(notices_item)
129
130        notices_truncated = self.notices_truncated
131
132        dry_run_incomplete = self.dry_run_incomplete
133
134        validation_stalled = self.validation_stalled
135
136        field_links: dict[str, Any] | Unset = UNSET
137        if not isinstance(self.field_links, Unset):
138            field_links = self.field_links.to_dict()
139
140        field_dict: dict[str, Any] = {}
141        field_dict.update(self.additional_properties)
142        field_dict.update(
143            {
144                "strategyId": strategy_id,
145                "validation": validation,
146            }
147        )
148        if compiled_at is not UNSET:
149            field_dict["compiledAt"] = compiled_at
150        if required_sources is not UNSET:
151            field_dict["requiredSources"] = required_sources
152        if validated_at is not UNSET:
153            field_dict["validatedAt"] = validated_at
154        if detail is not UNSET:
155            field_dict["detail"] = detail
156        if notices is not UNSET:
157            field_dict["notices"] = notices
158        if notices_truncated is not UNSET:
159            field_dict["noticesTruncated"] = notices_truncated
160        if dry_run_incomplete is not UNSET:
161            field_dict["dryRunIncomplete"] = dry_run_incomplete
162        if validation_stalled is not UNSET:
163            field_dict["validationStalled"] = validation_stalled
164        if field_links is not UNSET:
165            field_dict["_links"] = field_links
166
167        return field_dict
168
169    @classmethod
170    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
171        from ..models.notice import Notice
172        from ..models.strategy_links import StrategyLinks
173
174        d = dict(src_dict)
175        strategy_id = d.pop("strategyId")
176
177        validation = StrategyStateValidation(d.pop("validation"))
178
179        _compiled_at = d.pop("compiledAt", UNSET)
180        compiled_at: datetime.datetime | Unset
181        if isinstance(_compiled_at, Unset):
182            compiled_at = UNSET
183        else:
184            compiled_at = isoparse(_compiled_at)
185
186        _required_sources = d.pop("requiredSources", UNSET)
187        required_sources: list[StrategyStateRequiredSourcesItem] | Unset = UNSET
188        if _required_sources is not UNSET:
189            required_sources = []
190            for required_sources_item_data in _required_sources:
191                required_sources_item = StrategyStateRequiredSourcesItem(required_sources_item_data)
192
193                required_sources.append(required_sources_item)
194
195        _validated_at = d.pop("validatedAt", UNSET)
196        validated_at: datetime.datetime | Unset
197        if isinstance(_validated_at, Unset):
198            validated_at = UNSET
199        else:
200            validated_at = isoparse(_validated_at)
201
202        detail = d.pop("detail", UNSET)
203
204        _notices = d.pop("notices", UNSET)
205        notices: list[Notice] | Unset = UNSET
206        if _notices is not UNSET:
207            notices = []
208            for notices_item_data in _notices:
209                notices_item = Notice.from_dict(notices_item_data)
210
211                notices.append(notices_item)
212
213        notices_truncated = d.pop("noticesTruncated", UNSET)
214
215        dry_run_incomplete = d.pop("dryRunIncomplete", UNSET)
216
217        validation_stalled = d.pop("validationStalled", UNSET)
218
219        _field_links = d.pop("_links", UNSET)
220        field_links: StrategyLinks | Unset
221        if isinstance(_field_links, Unset):
222            field_links = UNSET
223        else:
224            field_links = StrategyLinks.from_dict(_field_links)
225
226        strategy_state = cls(
227            strategy_id=strategy_id,
228            validation=validation,
229            compiled_at=compiled_at,
230            required_sources=required_sources,
231            validated_at=validated_at,
232            detail=detail,
233            notices=notices,
234            notices_truncated=notices_truncated,
235            dry_run_incomplete=dry_run_incomplete,
236            validation_stalled=validation_stalled,
237            field_links=field_links,
238        )
239
240        strategy_state.additional_properties = d
241        return strategy_state
242
243    @property
244    def additional_keys(self) -> list[str]:
245        return list(self.additional_properties.keys())
246
247    def __getitem__(self, key: str) -> Any:
248        return self.additional_properties[key]
249
250    def __setitem__(self, key: str, value: Any) -> None:
251        self.additional_properties[key] = value
252
253    def __delitem__(self, key: str) -> None:
254        del self.additional_properties[key]
255
256    def __contains__(self, key: str) -> bool:
257        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. How much formatting the id ignores depends on
        the language — 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.
StrategyState( strategy_id: str, validation: StrategyStateValidation, compiled_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, required_sources: list[StrategyStateRequiredSourcesItem] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, validated_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, detail: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, notices: list[Notice] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, notices_truncated: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, dry_run_incomplete: bool | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, validation_stalled: bool | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, field_links: StrategyLinks | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

strategy_id: str
compiled_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
required_sources: list[StrategyStateRequiredSourcesItem] | qtsurfer.api.client._generated.types.Unset
validated_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
detail: str | qtsurfer.api.client._generated.types.Unset
notices: list[Notice] | qtsurfer.api.client._generated.types.Unset
notices_truncated: int | qtsurfer.api.client._generated.types.Unset
dry_run_incomplete: bool | qtsurfer.api.client._generated.types.Unset
validation_stalled: bool | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
101    def to_dict(self) -> dict[str, Any]:
102        strategy_id = self.strategy_id
103
104        validation = self.validation.value
105
106        compiled_at: str | Unset = UNSET
107        if not isinstance(self.compiled_at, Unset):
108            compiled_at = self.compiled_at.isoformat()
109
110        required_sources: list[str] | Unset = UNSET
111        if not isinstance(self.required_sources, Unset):
112            required_sources = []
113            for required_sources_item_data in self.required_sources:
114                required_sources_item = required_sources_item_data.value
115                required_sources.append(required_sources_item)
116
117        validated_at: str | Unset = UNSET
118        if not isinstance(self.validated_at, Unset):
119            validated_at = self.validated_at.isoformat()
120
121        detail = self.detail
122
123        notices: list[dict[str, Any]] | Unset = UNSET
124        if not isinstance(self.notices, Unset):
125            notices = []
126            for notices_item_data in self.notices:
127                notices_item = notices_item_data.to_dict()
128                notices.append(notices_item)
129
130        notices_truncated = self.notices_truncated
131
132        dry_run_incomplete = self.dry_run_incomplete
133
134        validation_stalled = self.validation_stalled
135
136        field_links: dict[str, Any] | Unset = UNSET
137        if not isinstance(self.field_links, Unset):
138            field_links = self.field_links.to_dict()
139
140        field_dict: dict[str, Any] = {}
141        field_dict.update(self.additional_properties)
142        field_dict.update(
143            {
144                "strategyId": strategy_id,
145                "validation": validation,
146            }
147        )
148        if compiled_at is not UNSET:
149            field_dict["compiledAt"] = compiled_at
150        if required_sources is not UNSET:
151            field_dict["requiredSources"] = required_sources
152        if validated_at is not UNSET:
153            field_dict["validatedAt"] = validated_at
154        if detail is not UNSET:
155            field_dict["detail"] = detail
156        if notices is not UNSET:
157            field_dict["notices"] = notices
158        if notices_truncated is not UNSET:
159            field_dict["noticesTruncated"] = notices_truncated
160        if dry_run_incomplete is not UNSET:
161            field_dict["dryRunIncomplete"] = dry_run_incomplete
162        if validation_stalled is not UNSET:
163            field_dict["validationStalled"] = validation_stalled
164        if field_links is not UNSET:
165            field_dict["_links"] = field_links
166
167        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
169    @classmethod
170    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
171        from ..models.notice import Notice
172        from ..models.strategy_links import StrategyLinks
173
174        d = dict(src_dict)
175        strategy_id = d.pop("strategyId")
176
177        validation = StrategyStateValidation(d.pop("validation"))
178
179        _compiled_at = d.pop("compiledAt", UNSET)
180        compiled_at: datetime.datetime | Unset
181        if isinstance(_compiled_at, Unset):
182            compiled_at = UNSET
183        else:
184            compiled_at = isoparse(_compiled_at)
185
186        _required_sources = d.pop("requiredSources", UNSET)
187        required_sources: list[StrategyStateRequiredSourcesItem] | Unset = UNSET
188        if _required_sources is not UNSET:
189            required_sources = []
190            for required_sources_item_data in _required_sources:
191                required_sources_item = StrategyStateRequiredSourcesItem(required_sources_item_data)
192
193                required_sources.append(required_sources_item)
194
195        _validated_at = d.pop("validatedAt", UNSET)
196        validated_at: datetime.datetime | Unset
197        if isinstance(_validated_at, Unset):
198            validated_at = UNSET
199        else:
200            validated_at = isoparse(_validated_at)
201
202        detail = d.pop("detail", UNSET)
203
204        _notices = d.pop("notices", UNSET)
205        notices: list[Notice] | Unset = UNSET
206        if _notices is not UNSET:
207            notices = []
208            for notices_item_data in _notices:
209                notices_item = Notice.from_dict(notices_item_data)
210
211                notices.append(notices_item)
212
213        notices_truncated = d.pop("noticesTruncated", UNSET)
214
215        dry_run_incomplete = d.pop("dryRunIncomplete", UNSET)
216
217        validation_stalled = d.pop("validationStalled", UNSET)
218
219        _field_links = d.pop("_links", UNSET)
220        field_links: StrategyLinks | Unset
221        if isinstance(_field_links, Unset):
222            field_links = UNSET
223        else:
224            field_links = StrategyLinks.from_dict(_field_links)
225
226        strategy_state = cls(
227            strategy_id=strategy_id,
228            validation=validation,
229            compiled_at=compiled_at,
230            required_sources=required_sources,
231            validated_at=validated_at,
232            detail=detail,
233            notices=notices,
234            notices_truncated=notices_truncated,
235            dry_run_incomplete=dry_run_incomplete,
236            validation_stalled=validation_stalled,
237            field_links=field_links,
238        )
239
240        strategy_state.additional_properties = d
241        return strategy_state
additional_keys: list[str]
243    @property
244    def additional_keys(self) -> list[str]:
245        return list(self.additional_properties.keys())
class StrategyStateRequiredSourcesItem(builtins.str, enum.Enum):
 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'.

FUNDINGRATE = <StrategyStateRequiredSourcesItem.FUNDINGRATE: 'FundingRate'>
class StrategyStateValidation(builtins.str, enum.Enum):
 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'.

FAILED = <StrategyStateValidation.FAILED: 'failed'>
NOT_VALIDATED = <StrategyStateValidation.NOT_VALIDATED: 'not_validated'>
PASSED = <StrategyStateValidation.PASSED: 'passed'>
PENDING = <StrategyStateValidation.PENDING: 'pending'>
class StrategySummary:
 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. How much formatting the id ignores depends on
 27                the language — see `POST /strategy` for exactly which rewrites preserve it and which do
 28                not.
 29                 Example: 6bsh31ikwkuivhtgcoa6s4.
 30            compiled_at (datetime.datetime | Unset): When the live compilation was produced.
 31            required_sources (list[str] | Unset): The market data this strategy needs. Absent, not empty, when it could
 32                not be established without constructing the strategy.
 33            deleted_at (datetime.datetime | Unset): When you deleted this strategy. Only ever present in `GET
 34                /strategies?includeDeleted=true`,
 35                and only on strategies you have deleted.
 36    """
 37
 38    strategy_id: str
 39    compiled_at: datetime.datetime | Unset = UNSET
 40    required_sources: list[str] | Unset = UNSET
 41    deleted_at: datetime.datetime | Unset = UNSET
 42    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 43
 44    def to_dict(self) -> dict[str, Any]:
 45        strategy_id = self.strategy_id
 46
 47        compiled_at: str | Unset = UNSET
 48        if not isinstance(self.compiled_at, Unset):
 49            compiled_at = self.compiled_at.isoformat()
 50
 51        required_sources: list[str] | Unset = UNSET
 52        if not isinstance(self.required_sources, Unset):
 53            required_sources = self.required_sources
 54
 55        deleted_at: str | Unset = UNSET
 56        if not isinstance(self.deleted_at, Unset):
 57            deleted_at = self.deleted_at.isoformat()
 58
 59        field_dict: dict[str, Any] = {}
 60        field_dict.update(self.additional_properties)
 61        field_dict.update(
 62            {
 63                "strategyId": strategy_id,
 64            }
 65        )
 66        if compiled_at is not UNSET:
 67            field_dict["compiledAt"] = compiled_at
 68        if required_sources is not UNSET:
 69            field_dict["requiredSources"] = required_sources
 70        if deleted_at is not UNSET:
 71            field_dict["deletedAt"] = deleted_at
 72
 73        return field_dict
 74
 75    @classmethod
 76    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 77        d = dict(src_dict)
 78        strategy_id = d.pop("strategyId")
 79
 80        _compiled_at = d.pop("compiledAt", UNSET)
 81        compiled_at: datetime.datetime | Unset
 82        if isinstance(_compiled_at, Unset):
 83            compiled_at = UNSET
 84        else:
 85            compiled_at = isoparse(_compiled_at)
 86
 87        required_sources = cast(list[str], d.pop("requiredSources", UNSET))
 88
 89        _deleted_at = d.pop("deletedAt", UNSET)
 90        deleted_at: datetime.datetime | Unset
 91        if isinstance(_deleted_at, Unset):
 92            deleted_at = UNSET
 93        else:
 94            deleted_at = isoparse(_deleted_at)
 95
 96        strategy_summary = cls(
 97            strategy_id=strategy_id,
 98            compiled_at=compiled_at,
 99            required_sources=required_sources,
100            deleted_at=deleted_at,
101        )
102
103        strategy_summary.additional_properties = d
104        return strategy_summary
105
106    @property
107    def additional_keys(self) -> list[str]:
108        return list(self.additional_properties.keys())
109
110    def __getitem__(self, key: str) -> Any:
111        return self.additional_properties[key]
112
113    def __setitem__(self, key: str, value: Any) -> None:
114        self.additional_properties[key] = value
115
116    def __delitem__(self, key: str) -> None:
117        del self.additional_properties[key]
118
119    def __contains__(self, key: str) -> bool:
120        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. How much formatting the id ignores depends on
        the language — 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.
    deleted_at (datetime.datetime | Unset): When you deleted this strategy. Only ever present in `GET
        /strategies?includeDeleted=true`,
        and only on strategies you have deleted.
StrategySummary( strategy_id: str, compiled_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, required_sources: list[str] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, deleted_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
27def __init__(self, strategy_id, compiled_at=attr_dict['compiled_at'].default, required_sources=attr_dict['required_sources'].default, deleted_at=attr_dict['deleted_at'].default):
28    self.strategy_id = strategy_id
29    self.compiled_at = compiled_at
30    self.required_sources = required_sources
31    self.deleted_at = deleted_at
32    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class StrategySummary.

strategy_id: str
compiled_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
required_sources: list[str] | qtsurfer.api.client._generated.types.Unset
deleted_at: datetime.datetime | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
44    def to_dict(self) -> dict[str, Any]:
45        strategy_id = self.strategy_id
46
47        compiled_at: str | Unset = UNSET
48        if not isinstance(self.compiled_at, Unset):
49            compiled_at = self.compiled_at.isoformat()
50
51        required_sources: list[str] | Unset = UNSET
52        if not isinstance(self.required_sources, Unset):
53            required_sources = self.required_sources
54
55        deleted_at: str | Unset = UNSET
56        if not isinstance(self.deleted_at, Unset):
57            deleted_at = self.deleted_at.isoformat()
58
59        field_dict: dict[str, Any] = {}
60        field_dict.update(self.additional_properties)
61        field_dict.update(
62            {
63                "strategyId": strategy_id,
64            }
65        )
66        if compiled_at is not UNSET:
67            field_dict["compiledAt"] = compiled_at
68        if required_sources is not UNSET:
69            field_dict["requiredSources"] = required_sources
70        if deleted_at is not UNSET:
71            field_dict["deletedAt"] = deleted_at
72
73        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 75    @classmethod
 76    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 77        d = dict(src_dict)
 78        strategy_id = d.pop("strategyId")
 79
 80        _compiled_at = d.pop("compiledAt", UNSET)
 81        compiled_at: datetime.datetime | Unset
 82        if isinstance(_compiled_at, Unset):
 83            compiled_at = UNSET
 84        else:
 85            compiled_at = isoparse(_compiled_at)
 86
 87        required_sources = cast(list[str], d.pop("requiredSources", UNSET))
 88
 89        _deleted_at = d.pop("deletedAt", UNSET)
 90        deleted_at: datetime.datetime | Unset
 91        if isinstance(_deleted_at, Unset):
 92            deleted_at = UNSET
 93        else:
 94            deleted_at = isoparse(_deleted_at)
 95
 96        strategy_summary = cls(
 97            strategy_id=strategy_id,
 98            compiled_at=compiled_at,
 99            required_sources=required_sources,
100            deleted_at=deleted_at,
101        )
102
103        strategy_summary.additional_properties = d
104        return strategy_summary
additional_keys: list[str]
106    @property
107    def additional_keys(self) -> list[str]:
108        return list(self.additional_properties.keys())
class SweepAxisType0:
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):

SweepAxisType0(from_: float, to: float, step: float)
25def __init__(self, from_, to, step):
26    self.from_ = from_
27    self.to = to
28    self.step = step

Method generated by attrs for class SweepAxisType0.

from_: float
to: float
step: float
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
class SweepAxisType1:
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]):

SweepAxisType1(values: list[bool | float])
23def __init__(self, values):
24    self.values = values

Method generated by attrs for class SweepAxisType1.

values: list[bool | float]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
class SweepBaseConfig:
 16@_attrs_define
 17class SweepBaseConfig:
 18    """
 19    Attributes:
 20        initial_funding (float | Unset):  Default: 100.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): Share of the free balance each entry locks, in percent (0-100]. Omitted,
 26            a backtest sizes every entry with everything available.
 27    """
 28
 29    initial_funding: float | Unset = 100.0
 30    fee_rate: float | Unset = 0.001
 31    buy_fee_rate: float | Unset = UNSET
 32    sell_fee_rate: float | Unset = UNSET
 33    fee_leg: SweepBaseConfigFeeLeg | Unset = SweepBaseConfigFeeLeg.RECEIVED
 34    percent_amount_to_lock: float | Unset = UNSET
 35    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 36
 37    def to_dict(self) -> dict[str, Any]:
 38        initial_funding = self.initial_funding
 39
 40        fee_rate = self.fee_rate
 41
 42        buy_fee_rate = self.buy_fee_rate
 43
 44        sell_fee_rate = self.sell_fee_rate
 45
 46        fee_leg: str | Unset = UNSET
 47        if not isinstance(self.fee_leg, Unset):
 48            fee_leg = self.fee_leg.value
 49
 50        percent_amount_to_lock = self.percent_amount_to_lock
 51
 52        field_dict: dict[str, Any] = {}
 53        field_dict.update(self.additional_properties)
 54        field_dict.update({})
 55        if initial_funding is not UNSET:
 56            field_dict["initialFunding"] = initial_funding
 57        if fee_rate is not UNSET:
 58            field_dict["feeRate"] = fee_rate
 59        if buy_fee_rate is not UNSET:
 60            field_dict["buyFeeRate"] = buy_fee_rate
 61        if sell_fee_rate is not UNSET:
 62            field_dict["sellFeeRate"] = sell_fee_rate
 63        if fee_leg is not UNSET:
 64            field_dict["feeLeg"] = fee_leg
 65        if percent_amount_to_lock is not UNSET:
 66            field_dict["percentAmountToLock"] = percent_amount_to_lock
 67
 68        return field_dict
 69
 70    @classmethod
 71    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 72        d = dict(src_dict)
 73        initial_funding = d.pop("initialFunding", UNSET)
 74
 75        fee_rate = d.pop("feeRate", UNSET)
 76
 77        buy_fee_rate = d.pop("buyFeeRate", UNSET)
 78
 79        sell_fee_rate = d.pop("sellFeeRate", UNSET)
 80
 81        _fee_leg = d.pop("feeLeg", UNSET)
 82        fee_leg: SweepBaseConfigFeeLeg | Unset
 83        if isinstance(_fee_leg, Unset):
 84            fee_leg = UNSET
 85        else:
 86            fee_leg = SweepBaseConfigFeeLeg(_fee_leg)
 87
 88        percent_amount_to_lock = d.pop("percentAmountToLock", UNSET)
 89
 90        sweep_base_config = cls(
 91            initial_funding=initial_funding,
 92            fee_rate=fee_rate,
 93            buy_fee_rate=buy_fee_rate,
 94            sell_fee_rate=sell_fee_rate,
 95            fee_leg=fee_leg,
 96            percent_amount_to_lock=percent_amount_to_lock,
 97        )
 98
 99        sweep_base_config.additional_properties = d
100        return sweep_base_config
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

Attributes: initial_funding (float | Unset): Default: 100.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): Share of the free balance each entry locks, in percent (0-100]. Omitted, a backtest sizes every entry with everything available.

SweepBaseConfig( initial_funding: float | qtsurfer.api.client._generated.types.Unset = 100.0, fee_rate: float | qtsurfer.api.client._generated.types.Unset = 0.001, buy_fee_rate: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, sell_fee_rate: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, fee_leg: SweepBaseConfigFeeLeg | qtsurfer.api.client._generated.types.Unset = <SweepBaseConfigFeeLeg.RECEIVED: 'RECEIVED'>, percent_amount_to_lock: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

initial_funding: float | qtsurfer.api.client._generated.types.Unset
fee_rate: float | qtsurfer.api.client._generated.types.Unset
buy_fee_rate: float | qtsurfer.api.client._generated.types.Unset
sell_fee_rate: float | qtsurfer.api.client._generated.types.Unset
fee_leg: SweepBaseConfigFeeLeg | qtsurfer.api.client._generated.types.Unset
percent_amount_to_lock: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
37    def to_dict(self) -> dict[str, Any]:
38        initial_funding = self.initial_funding
39
40        fee_rate = self.fee_rate
41
42        buy_fee_rate = self.buy_fee_rate
43
44        sell_fee_rate = self.sell_fee_rate
45
46        fee_leg: str | Unset = UNSET
47        if not isinstance(self.fee_leg, Unset):
48            fee_leg = self.fee_leg.value
49
50        percent_amount_to_lock = self.percent_amount_to_lock
51
52        field_dict: dict[str, Any] = {}
53        field_dict.update(self.additional_properties)
54        field_dict.update({})
55        if initial_funding is not UNSET:
56            field_dict["initialFunding"] = initial_funding
57        if fee_rate is not UNSET:
58            field_dict["feeRate"] = fee_rate
59        if buy_fee_rate is not UNSET:
60            field_dict["buyFeeRate"] = buy_fee_rate
61        if sell_fee_rate is not UNSET:
62            field_dict["sellFeeRate"] = sell_fee_rate
63        if fee_leg is not UNSET:
64            field_dict["feeLeg"] = fee_leg
65        if percent_amount_to_lock is not UNSET:
66            field_dict["percentAmountToLock"] = percent_amount_to_lock
67
68        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 70    @classmethod
 71    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 72        d = dict(src_dict)
 73        initial_funding = d.pop("initialFunding", UNSET)
 74
 75        fee_rate = d.pop("feeRate", UNSET)
 76
 77        buy_fee_rate = d.pop("buyFeeRate", UNSET)
 78
 79        sell_fee_rate = d.pop("sellFeeRate", UNSET)
 80
 81        _fee_leg = d.pop("feeLeg", UNSET)
 82        fee_leg: SweepBaseConfigFeeLeg | Unset
 83        if isinstance(_fee_leg, Unset):
 84            fee_leg = UNSET
 85        else:
 86            fee_leg = SweepBaseConfigFeeLeg(_fee_leg)
 87
 88        percent_amount_to_lock = d.pop("percentAmountToLock", UNSET)
 89
 90        sweep_base_config = cls(
 91            initial_funding=initial_funding,
 92            fee_rate=fee_rate,
 93            buy_fee_rate=buy_fee_rate,
 94            sell_fee_rate=sell_fee_rate,
 95            fee_leg=fee_leg,
 96            percent_amount_to_lock=percent_amount_to_lock,
 97        )
 98
 99        sweep_base_config.additional_properties = d
100        return sweep_base_config
additional_keys: list[str]
102    @property
103    def additional_keys(self) -> list[str]:
104        return list(self.additional_properties.keys())
class SweepBaseConfigFeeLeg(builtins.str, enum.Enum):
 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'.

BASE = <SweepBaseConfigFeeLeg.BASE: 'BASE'>
QUOTE = <SweepBaseConfigFeeLeg.QUOTE: 'QUOTE'>
RECEIVED = <SweepBaseConfigFeeLeg.RECEIVED: 'RECEIVED'>
class SweepHeatmap:
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):

SweepHeatmap( param_a: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, param_b: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, cells: list[SweepHeatmapCell] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

param_a: str | qtsurfer.api.client._generated.types.Unset
param_b: str | qtsurfer.api.client._generated.types.Unset
cells: list[SweepHeatmapCell] | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
85    @property
86    def additional_keys(self) -> list[str]:
87        return list(self.additional_properties.keys())
class SweepHeatmapCell:
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):

SweepHeatmapCell( value_a: typing.Any | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, value_b: typing.Any | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, count: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, best: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, mean: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

value_a: typing.Any | qtsurfer.api.client._generated.types.Unset
value_b: typing.Any | qtsurfer.api.client._generated.types.Unset
count: int | qtsurfer.api.client._generated.types.Unset
best: float | qtsurfer.api.client._generated.types.Unset
mean: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
84    @property
85    def additional_keys(self) -> list[str]:
86        return list(self.additional_properties.keys())
class SweepMarginal:
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):

SweepMarginal( param: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, points: list[SweepMarginalPoint] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

param: str | qtsurfer.api.client._generated.types.Unset
points: list[SweepMarginalPoint] | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
76    @property
77    def additional_keys(self) -> list[str]:
78        return list(self.additional_properties.keys())
class SweepMarginalPoint:
 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):
SweepMarginalPoint( value: typing.Any | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, count: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, best: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, mean: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, worst: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

value: typing.Any | qtsurfer.api.client._generated.types.Unset
count: int | qtsurfer.api.client._generated.types.Unset
best: float | qtsurfer.api.client._generated.types.Unset
mean: float | qtsurfer.api.client._generated.types.Unset
worst: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
86    @property
87    def additional_keys(self) -> list[str]:
88        return list(self.additional_properties.keys())
class SweepProgress:
 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): Shards (or folds) that have not finished yet. On a cancelled sweep, `0` is what says every
 28                run that was in flight has finished and the leaderboard is complete: `CANCELLED` is reported before that.
 29            failed_shards (int): Shards (or folds) that failed and will not be retried. Distinct from `aborted`: this counts
 30                whole units that never reported, not runs that ran badly.
 31            retrying (int): Units whose last attempt failed on something transient — an I/O error, a worker that died mid-
 32                read — and which are queued to be attempted again. Not counted as failures, because they have not failed yet; a
 33                sweep with a non-zero value here is still expected to complete.
 34            not_started (int): Units that have not reported anything yet. Covers both work still queued behind other work
 35                and work claimed by a worker that stopped before it began, which is why a sweep with a persistent value here and
 36                a rising `stalledSeconds` is worth looking at.
 37            stalled_seconds (int | Unset): Seconds since anything last advanced. Omitted on a finished sweep, where it would
 38                only measure how long ago it finished, and on sweeps submitted before this field existed.
 39            eta_seconds (int | Unset): Rough seconds remaining, extrapolated from the rate observed so far and assuming
 40                nothing else competes for workers. Runs conservative in practice — it has measured 2–5× long when a sweep spent
 41                part of its life waiting to be retried, since that wait dilutes the observed rate. **Omitted, never zero, when
 42                it cannot be computed**: a sweep with nothing finished yet has no rate to extrapolate from, and a zero would
 43                read as "about to finish". Excludes queue wait entirely; `retrying` and `stalledSeconds` are where that shows
 44                up.
 45    """
 46
 47    done: int
 48    total: int
 49    aborted: int
 50    shard_count: int
 51    pending_shards: int
 52    failed_shards: int
 53    retrying: int
 54    not_started: int
 55    stalled_seconds: int | Unset = UNSET
 56    eta_seconds: int | Unset = UNSET
 57    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 58
 59    def to_dict(self) -> dict[str, Any]:
 60        done = self.done
 61
 62        total = self.total
 63
 64        aborted = self.aborted
 65
 66        shard_count = self.shard_count
 67
 68        pending_shards = self.pending_shards
 69
 70        failed_shards = self.failed_shards
 71
 72        retrying = self.retrying
 73
 74        not_started = self.not_started
 75
 76        stalled_seconds = self.stalled_seconds
 77
 78        eta_seconds = self.eta_seconds
 79
 80        field_dict: dict[str, Any] = {}
 81        field_dict.update(self.additional_properties)
 82        field_dict.update(
 83            {
 84                "done": done,
 85                "total": total,
 86                "aborted": aborted,
 87                "shardCount": shard_count,
 88                "pendingShards": pending_shards,
 89                "failedShards": failed_shards,
 90                "retrying": retrying,
 91                "notStarted": not_started,
 92            }
 93        )
 94        if stalled_seconds is not UNSET:
 95            field_dict["stalledSeconds"] = stalled_seconds
 96        if eta_seconds is not UNSET:
 97            field_dict["etaSeconds"] = eta_seconds
 98
 99        return field_dict
100
101    @classmethod
102    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
103        d = dict(src_dict)
104        done = d.pop("done")
105
106        total = d.pop("total")
107
108        aborted = d.pop("aborted")
109
110        shard_count = d.pop("shardCount")
111
112        pending_shards = d.pop("pendingShards")
113
114        failed_shards = d.pop("failedShards")
115
116        retrying = d.pop("retrying")
117
118        not_started = d.pop("notStarted")
119
120        stalled_seconds = d.pop("stalledSeconds", UNSET)
121
122        eta_seconds = d.pop("etaSeconds", UNSET)
123
124        sweep_progress = cls(
125            done=done,
126            total=total,
127            aborted=aborted,
128            shard_count=shard_count,
129            pending_shards=pending_shards,
130            failed_shards=failed_shards,
131            retrying=retrying,
132            not_started=not_started,
133            stalled_seconds=stalled_seconds,
134            eta_seconds=eta_seconds,
135        )
136
137        sweep_progress.additional_properties = d
138        return sweep_progress
139
140    @property
141    def additional_keys(self) -> list[str]:
142        return list(self.additional_properties.keys())
143
144    def __getitem__(self, key: str) -> Any:
145        return self.additional_properties[key]
146
147    def __setitem__(self, key: str, value: Any) -> None:
148        self.additional_properties[key] = value
149
150    def __delitem__(self, key: str) -> None:
151        del self.additional_properties[key]
152
153    def __contains__(self, key: str) -> bool:
154        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): Shards (or folds) that have not finished yet. On a cancelled sweep, `0` is what says every
        run that was in flight has finished and the leaderboard is complete: `CANCELLED` is reported before that.
    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.
SweepProgress( done: int, total: int, aborted: int, shard_count: int, pending_shards: int, failed_shards: int, retrying: int, not_started: int, stalled_seconds: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, eta_seconds: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

done: int
total: int
aborted: int
shard_count: int
pending_shards: int
failed_shards: int
retrying: int
not_started: int
stalled_seconds: int | qtsurfer.api.client._generated.types.Unset
eta_seconds: int | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
59    def to_dict(self) -> dict[str, Any]:
60        done = self.done
61
62        total = self.total
63
64        aborted = self.aborted
65
66        shard_count = self.shard_count
67
68        pending_shards = self.pending_shards
69
70        failed_shards = self.failed_shards
71
72        retrying = self.retrying
73
74        not_started = self.not_started
75
76        stalled_seconds = self.stalled_seconds
77
78        eta_seconds = self.eta_seconds
79
80        field_dict: dict[str, Any] = {}
81        field_dict.update(self.additional_properties)
82        field_dict.update(
83            {
84                "done": done,
85                "total": total,
86                "aborted": aborted,
87                "shardCount": shard_count,
88                "pendingShards": pending_shards,
89                "failedShards": failed_shards,
90                "retrying": retrying,
91                "notStarted": not_started,
92            }
93        )
94        if stalled_seconds is not UNSET:
95            field_dict["stalledSeconds"] = stalled_seconds
96        if eta_seconds is not UNSET:
97            field_dict["etaSeconds"] = eta_seconds
98
99        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
101    @classmethod
102    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
103        d = dict(src_dict)
104        done = d.pop("done")
105
106        total = d.pop("total")
107
108        aborted = d.pop("aborted")
109
110        shard_count = d.pop("shardCount")
111
112        pending_shards = d.pop("pendingShards")
113
114        failed_shards = d.pop("failedShards")
115
116        retrying = d.pop("retrying")
117
118        not_started = d.pop("notStarted")
119
120        stalled_seconds = d.pop("stalledSeconds", UNSET)
121
122        eta_seconds = d.pop("etaSeconds", UNSET)
123
124        sweep_progress = cls(
125            done=done,
126            total=total,
127            aborted=aborted,
128            shard_count=shard_count,
129            pending_shards=pending_shards,
130            failed_shards=failed_shards,
131            retrying=retrying,
132            not_started=not_started,
133            stalled_seconds=stalled_seconds,
134            eta_seconds=eta_seconds,
135        )
136
137        sweep_progress.additional_properties = d
138        return sweep_progress
additional_keys: list[str]
140    @property
141    def additional_keys(self) -> list[str]:
142        return list(self.additional_properties.keys())
class SweepRunRow:
 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): Same units as `pnlTotalPercent` on the single-run result — percent (0-100 scale).
 30        cagr (float): Same units as `cagr` on the single-run result — a ratio, not a percent.
 31        max_dd_pct (float): Same units as `maxDrawdownPercent` on the single-run result — percent (0-100 scale).
 32        trades (int):
 33        win_rate (float): Same units as `winRate` on the single-run result — a fraction, 0.0-1.0 (a rate, not a
 34            percent).
 35        below_trade_floor (bool):
 36        aborted (bool):
 37        runtime_ms (int):
 38        rank (int | Unset): Present only in the `ranked` view.
 39        plateau_score (float | Unset): The objective of the worst run in this point's immediate neighbourhood — how well
 40            the region around it holds up, not how well it scored itself. Present only in the `ranked` view when plateau
 41            ranking applied. Always read together with `neighbourCount`.
 42        neighbour_count (int | Unset): How many neighbouring parameter points backed the `plateauScore`. Zero means the
 43            point had no neighbours in the grid, so its score is unevidenced rather than confirmed — the value alone cannot
 44            be distinguished from a genuinely robust one.
 45        deflated_sharpe (float | Unset): Probability that this run's Sharpe reflects real edge rather than the best draw
 46            from however many parameter vectors were tried. Above ~0.95 the result survives the multiple-testing correction;
 47            near 0.5 or below it is indistinguishable from the best of a pile of coin flips. Absent on aborted runs, on
 48            sweeps with too few trials to establish any dispersion to deflate against, on runs with fewer than 3 period
 49            returns, and on a degenerate (near-constant) return series — all cases where the underlying statistic isn't
 50            meaningfully computable, rather than genuinely zero. A present value is the computed probability, however small.
 51        equity_curve (EquityCurveResult | Unset): An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`,
 52            `timestamps` + `equities` (parallel arrays) when `SHORT`. Used identically wherever a curve is returned — a
 53            plain backtest's inline `equityCurve` and a sweep row's `equityCurve` are the same type. `url` is present
 54            *instead of* any points when the curve is served by pointer rather than inline (a sweep row's top-N winners
 55            only): `GET` it separately to fetch this exact same shape with the points populated.
 56    """
 57
 58    run_ix: int
 59    params: SweepRunRowParams
 60    sharpe: float
 61    sortino: float
 62    pnl: float
 63    pnl_pct: float
 64    cagr: float
 65    max_dd_pct: float
 66    trades: int
 67    win_rate: float
 68    below_trade_floor: bool
 69    aborted: bool
 70    runtime_ms: int
 71    rank: int | Unset = UNSET
 72    plateau_score: float | Unset = UNSET
 73    neighbour_count: int | Unset = UNSET
 74    deflated_sharpe: float | Unset = UNSET
 75    equity_curve: EquityCurveResult | Unset = UNSET
 76    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 77
 78    def to_dict(self) -> dict[str, Any]:
 79        run_ix = self.run_ix
 80
 81        params = self.params.to_dict()
 82
 83        sharpe = self.sharpe
 84
 85        sortino = self.sortino
 86
 87        pnl = self.pnl
 88
 89        pnl_pct = self.pnl_pct
 90
 91        cagr = self.cagr
 92
 93        max_dd_pct = self.max_dd_pct
 94
 95        trades = self.trades
 96
 97        win_rate = self.win_rate
 98
 99        below_trade_floor = self.below_trade_floor
100
101        aborted = self.aborted
102
103        runtime_ms = self.runtime_ms
104
105        rank = self.rank
106
107        plateau_score = self.plateau_score
108
109        neighbour_count = self.neighbour_count
110
111        deflated_sharpe = self.deflated_sharpe
112
113        equity_curve: dict[str, Any] | Unset = UNSET
114        if not isinstance(self.equity_curve, Unset):
115            equity_curve = self.equity_curve.to_dict()
116
117        field_dict: dict[str, Any] = {}
118        field_dict.update(self.additional_properties)
119        field_dict.update(
120            {
121                "runIx": run_ix,
122                "params": params,
123                "sharpe": sharpe,
124                "sortino": sortino,
125                "pnl": pnl,
126                "pnlPct": pnl_pct,
127                "cagr": cagr,
128                "maxDdPct": max_dd_pct,
129                "trades": trades,
130                "winRate": win_rate,
131                "belowTradeFloor": below_trade_floor,
132                "aborted": aborted,
133                "runtimeMs": runtime_ms,
134            }
135        )
136        if rank is not UNSET:
137            field_dict["rank"] = rank
138        if plateau_score is not UNSET:
139            field_dict["plateauScore"] = plateau_score
140        if neighbour_count is not UNSET:
141            field_dict["neighbourCount"] = neighbour_count
142        if deflated_sharpe is not UNSET:
143            field_dict["deflatedSharpe"] = deflated_sharpe
144        if equity_curve is not UNSET:
145            field_dict["equityCurve"] = equity_curve
146
147        return field_dict
148
149    @classmethod
150    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
151        from ..models.equity_curve_result import EquityCurveResult
152        from ..models.sweep_run_row_params import SweepRunRowParams
153
154        d = dict(src_dict)
155        run_ix = d.pop("runIx")
156
157        params = SweepRunRowParams.from_dict(d.pop("params"))
158
159        sharpe = d.pop("sharpe")
160
161        sortino = d.pop("sortino")
162
163        pnl = d.pop("pnl")
164
165        pnl_pct = d.pop("pnlPct")
166
167        cagr = d.pop("cagr")
168
169        max_dd_pct = d.pop("maxDdPct")
170
171        trades = d.pop("trades")
172
173        win_rate = d.pop("winRate")
174
175        below_trade_floor = d.pop("belowTradeFloor")
176
177        aborted = d.pop("aborted")
178
179        runtime_ms = d.pop("runtimeMs")
180
181        rank = d.pop("rank", UNSET)
182
183        plateau_score = d.pop("plateauScore", UNSET)
184
185        neighbour_count = d.pop("neighbourCount", UNSET)
186
187        deflated_sharpe = d.pop("deflatedSharpe", UNSET)
188
189        _equity_curve = d.pop("equityCurve", UNSET)
190        equity_curve: EquityCurveResult | Unset
191        if isinstance(_equity_curve, Unset):
192            equity_curve = UNSET
193        else:
194            equity_curve = EquityCurveResult.from_dict(_equity_curve)
195
196        sweep_run_row = cls(
197            run_ix=run_ix,
198            params=params,
199            sharpe=sharpe,
200            sortino=sortino,
201            pnl=pnl,
202            pnl_pct=pnl_pct,
203            cagr=cagr,
204            max_dd_pct=max_dd_pct,
205            trades=trades,
206            win_rate=win_rate,
207            below_trade_floor=below_trade_floor,
208            aborted=aborted,
209            runtime_ms=runtime_ms,
210            rank=rank,
211            plateau_score=plateau_score,
212            neighbour_count=neighbour_count,
213            deflated_sharpe=deflated_sharpe,
214            equity_curve=equity_curve,
215        )
216
217        sweep_run_row.additional_properties = d
218        return sweep_run_row
219
220    @property
221    def additional_keys(self) -> list[str]:
222        return list(self.additional_properties.keys())
223
224    def __getitem__(self, key: str) -> Any:
225        return self.additional_properties[key]
226
227    def __setitem__(self, key: str, value: Any) -> None:
228        self.additional_properties[key] = value
229
230    def __delitem__(self, key: str) -> None:
231        del self.additional_properties[key]
232
233    def __contains__(self, key: str) -> bool:
234        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): Same units as pnlTotalPercent on the single-run result — percent (0-100 scale). cagr (float): Same units as cagr on the single-run result — a ratio, not a percent. max_dd_pct (float): Same units as maxDrawdownPercent on the single-run result — percent (0-100 scale). trades (int): win_rate (float): Same units as winRate on the single-run result — a fraction, 0.0-1.0 (a rate, not a percent). 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, on sweeps with too few trials to establish any dispersion to deflate against, on runs with fewer than 3 period returns, and on a degenerate (near-constant) return series — all cases where the underlying statistic isn't meaningfully computable, rather than genuinely zero. A present value is the computed probability, however small. 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.

SweepRunRow( run_ix: int, params: SweepRunRowParams, sharpe: float, sortino: float, pnl: float, 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 | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, plateau_score: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, neighbour_count: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, deflated_sharpe: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, equity_curve: EquityCurveResult | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

run_ix: int
sharpe: float
sortino: float
pnl: float
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 | qtsurfer.api.client._generated.types.Unset
plateau_score: float | qtsurfer.api.client._generated.types.Unset
neighbour_count: int | qtsurfer.api.client._generated.types.Unset
deflated_sharpe: float | qtsurfer.api.client._generated.types.Unset
equity_curve: EquityCurveResult | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
 78    def to_dict(self) -> dict[str, Any]:
 79        run_ix = self.run_ix
 80
 81        params = self.params.to_dict()
 82
 83        sharpe = self.sharpe
 84
 85        sortino = self.sortino
 86
 87        pnl = self.pnl
 88
 89        pnl_pct = self.pnl_pct
 90
 91        cagr = self.cagr
 92
 93        max_dd_pct = self.max_dd_pct
 94
 95        trades = self.trades
 96
 97        win_rate = self.win_rate
 98
 99        below_trade_floor = self.below_trade_floor
100
101        aborted = self.aborted
102
103        runtime_ms = self.runtime_ms
104
105        rank = self.rank
106
107        plateau_score = self.plateau_score
108
109        neighbour_count = self.neighbour_count
110
111        deflated_sharpe = self.deflated_sharpe
112
113        equity_curve: dict[str, Any] | Unset = UNSET
114        if not isinstance(self.equity_curve, Unset):
115            equity_curve = self.equity_curve.to_dict()
116
117        field_dict: dict[str, Any] = {}
118        field_dict.update(self.additional_properties)
119        field_dict.update(
120            {
121                "runIx": run_ix,
122                "params": params,
123                "sharpe": sharpe,
124                "sortino": sortino,
125                "pnl": pnl,
126                "pnlPct": pnl_pct,
127                "cagr": cagr,
128                "maxDdPct": max_dd_pct,
129                "trades": trades,
130                "winRate": win_rate,
131                "belowTradeFloor": below_trade_floor,
132                "aborted": aborted,
133                "runtimeMs": runtime_ms,
134            }
135        )
136        if rank is not UNSET:
137            field_dict["rank"] = rank
138        if plateau_score is not UNSET:
139            field_dict["plateauScore"] = plateau_score
140        if neighbour_count is not UNSET:
141            field_dict["neighbourCount"] = neighbour_count
142        if deflated_sharpe is not UNSET:
143            field_dict["deflatedSharpe"] = deflated_sharpe
144        if equity_curve is not UNSET:
145            field_dict["equityCurve"] = equity_curve
146
147        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
149    @classmethod
150    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
151        from ..models.equity_curve_result import EquityCurveResult
152        from ..models.sweep_run_row_params import SweepRunRowParams
153
154        d = dict(src_dict)
155        run_ix = d.pop("runIx")
156
157        params = SweepRunRowParams.from_dict(d.pop("params"))
158
159        sharpe = d.pop("sharpe")
160
161        sortino = d.pop("sortino")
162
163        pnl = d.pop("pnl")
164
165        pnl_pct = d.pop("pnlPct")
166
167        cagr = d.pop("cagr")
168
169        max_dd_pct = d.pop("maxDdPct")
170
171        trades = d.pop("trades")
172
173        win_rate = d.pop("winRate")
174
175        below_trade_floor = d.pop("belowTradeFloor")
176
177        aborted = d.pop("aborted")
178
179        runtime_ms = d.pop("runtimeMs")
180
181        rank = d.pop("rank", UNSET)
182
183        plateau_score = d.pop("plateauScore", UNSET)
184
185        neighbour_count = d.pop("neighbourCount", UNSET)
186
187        deflated_sharpe = d.pop("deflatedSharpe", UNSET)
188
189        _equity_curve = d.pop("equityCurve", UNSET)
190        equity_curve: EquityCurveResult | Unset
191        if isinstance(_equity_curve, Unset):
192            equity_curve = UNSET
193        else:
194            equity_curve = EquityCurveResult.from_dict(_equity_curve)
195
196        sweep_run_row = cls(
197            run_ix=run_ix,
198            params=params,
199            sharpe=sharpe,
200            sortino=sortino,
201            pnl=pnl,
202            pnl_pct=pnl_pct,
203            cagr=cagr,
204            max_dd_pct=max_dd_pct,
205            trades=trades,
206            win_rate=win_rate,
207            below_trade_floor=below_trade_floor,
208            aborted=aborted,
209            runtime_ms=runtime_ms,
210            rank=rank,
211            plateau_score=plateau_score,
212            neighbour_count=neighbour_count,
213            deflated_sharpe=deflated_sharpe,
214            equity_curve=equity_curve,
215        )
216
217        sweep_run_row.additional_properties = d
218        return sweep_run_row
additional_keys: list[str]
220    @property
221    def additional_keys(self) -> list[str]:
222        return list(self.additional_properties.keys())
class SweepRunRowParams:
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
SweepRunRowParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class SweepRunRowParams.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
34    @property
35    def additional_keys(self) -> list[str]:
36        return list(self.additional_properties.keys())
class SweepSensitivity:
 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.
SweepSensitivity( sweep_id: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, status: SweepSensitivityStatus | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, objective: SweepSensitivityObjective | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, rows_analysed: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, marginals: list[SweepMarginal] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, heatmaps: list[SweepHeatmap] | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, heatmaps_truncated: bool | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

sweep_id: str | qtsurfer.api.client._generated.types.Unset
status: SweepSensitivityStatus | qtsurfer.api.client._generated.types.Unset
objective: SweepSensitivityObjective | qtsurfer.api.client._generated.types.Unset
rows_analysed: int | qtsurfer.api.client._generated.types.Unset
marginals: list[SweepMarginal] | qtsurfer.api.client._generated.types.Unset
heatmaps: list[SweepHeatmap] | qtsurfer.api.client._generated.types.Unset
heatmaps_truncated: bool | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
154    @property
155    def additional_keys(self) -> list[str]:
156        return list(self.additional_properties.keys())
class SweepSensitivityObjective(builtins.str, enum.Enum):
 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'.

MAXDD = <SweepSensitivityObjective.MAXDD: 'maxdd'>
SHARPE = <SweepSensitivityObjective.SHARPE: 'sharpe'>
SORTINO = <SweepSensitivityObjective.SORTINO: 'sortino'>
class SweepSensitivityStatus(builtins.str, enum.Enum):
 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'.

CANCELLED = <SweepSensitivityStatus.CANCELLED: 'CANCELLED'>
COMPLETED = <SweepSensitivityStatus.COMPLETED: 'COMPLETED'>
PARTIAL = <SweepSensitivityStatus.PARTIAL: 'PARTIAL'>
RUNNING = <SweepSensitivityStatus.RUNNING: 'RUNNING'>
class SweepSpecRequest:
 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): `grid` runs every combination of the axes and is held to your plan's
 31            `maxSweepCartesian` (`GET /account`); `random` and `lhs` run `samples` combinations and are not.
 32             Default: SweepSpecRequestSampler.GRID.
 33        seed (int | Unset): Reproducibility seed. If omitted, the server generates one with Java's
 34            `L64X128MixRandom` generator and returns the effective value. The range
 35            is limited to JavaScript-safe integers so generated clients can replay it exactly.
 36        samples (int | Unset): Number of samples for `random` and `lhs`; ignored by `grid`.
 37        objective (SweepSpecRequestObjective | Unset):  Default: SweepSpecRequestObjective.SHARPE.
 38    """
 39
 40    params: SweepSpecRequestParams
 41    sampler: SweepSpecRequestSampler | Unset = SweepSpecRequestSampler.GRID
 42    seed: int | Unset = UNSET
 43    samples: int | Unset = UNSET
 44    objective: SweepSpecRequestObjective | Unset = SweepSpecRequestObjective.SHARPE
 45    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 46
 47    def to_dict(self) -> dict[str, Any]:
 48        params = self.params.to_dict()
 49
 50        sampler: str | Unset = UNSET
 51        if not isinstance(self.sampler, Unset):
 52            sampler = self.sampler.value
 53
 54        seed = self.seed
 55
 56        samples = self.samples
 57
 58        objective: str | Unset = UNSET
 59        if not isinstance(self.objective, Unset):
 60            objective = self.objective.value
 61
 62        field_dict: dict[str, Any] = {}
 63        field_dict.update(self.additional_properties)
 64        field_dict.update(
 65            {
 66                "params": params,
 67            }
 68        )
 69        if sampler is not UNSET:
 70            field_dict["sampler"] = sampler
 71        if seed is not UNSET:
 72            field_dict["seed"] = seed
 73        if samples is not UNSET:
 74            field_dict["samples"] = samples
 75        if objective is not UNSET:
 76            field_dict["objective"] = objective
 77
 78        return field_dict
 79
 80    @classmethod
 81    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 82        from ..models.sweep_spec_request_params import SweepSpecRequestParams
 83
 84        d = dict(src_dict)
 85        params = SweepSpecRequestParams.from_dict(d.pop("params"))
 86
 87        _sampler = d.pop("sampler", UNSET)
 88        sampler: SweepSpecRequestSampler | Unset
 89        if isinstance(_sampler, Unset):
 90            sampler = UNSET
 91        else:
 92            sampler = SweepSpecRequestSampler(_sampler)
 93
 94        seed = d.pop("seed", UNSET)
 95
 96        samples = d.pop("samples", UNSET)
 97
 98        _objective = d.pop("objective", UNSET)
 99        objective: SweepSpecRequestObjective | Unset
100        if isinstance(_objective, Unset):
101            objective = UNSET
102        else:
103            objective = SweepSpecRequestObjective(_objective)
104
105        sweep_spec_request = cls(
106            params=params,
107            sampler=sampler,
108            seed=seed,
109            samples=samples,
110            objective=objective,
111        )
112
113        sweep_spec_request.additional_properties = d
114        return sweep_spec_request
115
116    @property
117    def additional_keys(self) -> list[str]:
118        return list(self.additional_properties.keys())
119
120    def __getitem__(self, key: str) -> Any:
121        return self.additional_properties[key]
122
123    def __setitem__(self, key: str, value: Any) -> None:
124        self.additional_properties[key] = value
125
126    def __delitem__(self, key: str) -> None:
127        del self.additional_properties[key]
128
129    def __contains__(self, key: str) -> bool:
130        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): grid runs every combination of the axes and is held to your plan's maxSweepCartesian (GET /account); random and lhs run samples combinations and are not. 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.

SweepSpecRequest( params: SweepSpecRequestParams, sampler: SweepSpecRequestSampler | qtsurfer.api.client._generated.types.Unset = <SweepSpecRequestSampler.GRID: 'grid'>, seed: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, samples: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, objective: SweepSpecRequestObjective | qtsurfer.api.client._generated.types.Unset = <SweepSpecRequestObjective.SHARPE: '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.

sampler: SweepSpecRequestSampler | qtsurfer.api.client._generated.types.Unset
seed: int | qtsurfer.api.client._generated.types.Unset
samples: int | qtsurfer.api.client._generated.types.Unset
objective: SweepSpecRequestObjective | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
47    def to_dict(self) -> dict[str, Any]:
48        params = self.params.to_dict()
49
50        sampler: str | Unset = UNSET
51        if not isinstance(self.sampler, Unset):
52            sampler = self.sampler.value
53
54        seed = self.seed
55
56        samples = self.samples
57
58        objective: str | Unset = UNSET
59        if not isinstance(self.objective, Unset):
60            objective = self.objective.value
61
62        field_dict: dict[str, Any] = {}
63        field_dict.update(self.additional_properties)
64        field_dict.update(
65            {
66                "params": params,
67            }
68        )
69        if sampler is not UNSET:
70            field_dict["sampler"] = sampler
71        if seed is not UNSET:
72            field_dict["seed"] = seed
73        if samples is not UNSET:
74            field_dict["samples"] = samples
75        if objective is not UNSET:
76            field_dict["objective"] = objective
77
78        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 80    @classmethod
 81    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 82        from ..models.sweep_spec_request_params import SweepSpecRequestParams
 83
 84        d = dict(src_dict)
 85        params = SweepSpecRequestParams.from_dict(d.pop("params"))
 86
 87        _sampler = d.pop("sampler", UNSET)
 88        sampler: SweepSpecRequestSampler | Unset
 89        if isinstance(_sampler, Unset):
 90            sampler = UNSET
 91        else:
 92            sampler = SweepSpecRequestSampler(_sampler)
 93
 94        seed = d.pop("seed", UNSET)
 95
 96        samples = d.pop("samples", UNSET)
 97
 98        _objective = d.pop("objective", UNSET)
 99        objective: SweepSpecRequestObjective | Unset
100        if isinstance(_objective, Unset):
101            objective = UNSET
102        else:
103            objective = SweepSpecRequestObjective(_objective)
104
105        sweep_spec_request = cls(
106            params=params,
107            sampler=sampler,
108            seed=seed,
109            samples=samples,
110            objective=objective,
111        )
112
113        sweep_spec_request.additional_properties = d
114        return sweep_spec_request
additional_keys: list[str]
116    @property
117    def additional_keys(self) -> list[str]:
118        return list(self.additional_properties.keys())
class SweepSpecRequestObjective(builtins.str, enum.Enum):
 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'.

MAXDD = <SweepSpecRequestObjective.MAXDD: 'maxdd'>
SHARPE = <SweepSpecRequestObjective.SHARPE: 'sharpe'>
SORTINO = <SweepSpecRequestObjective.SORTINO: 'sortino'>
class SweepSpecRequestParams:
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
SweepSpecRequestParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class SweepSpecRequestParams.

additional_properties: dict[str, SweepAxisType0 | SweepAxisType1]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
69    @property
70    def additional_keys(self) -> list[str]:
71        return list(self.additional_properties.keys())
class SweepSpecRequestSampler(builtins.str, enum.Enum):
 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'.

GRID = <SweepSpecRequestSampler.GRID: 'grid'>
RANDOM = <SweepSpecRequestSampler.RANDOM: 'random'>
class UpdateLiveParamsRequest:
17@_attrs_define
18class UpdateLiveParamsRequest:
19    """
20    Attributes:
21        params (UpdateLiveParamsRequestParams): Must be non-empty; every key must be a property your strategy declares.
22    """
23
24    params: UpdateLiveParamsRequestParams
25    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
26
27    def to_dict(self) -> dict[str, Any]:
28        params = self.params.to_dict()
29
30        field_dict: dict[str, Any] = {}
31        field_dict.update(self.additional_properties)
32        field_dict.update(
33            {
34                "params": params,
35            }
36        )
37
38        return field_dict
39
40    @classmethod
41    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
42        from ..models.update_live_params_request_params import UpdateLiveParamsRequestParams
43
44        d = dict(src_dict)
45        params = UpdateLiveParamsRequestParams.from_dict(d.pop("params"))
46
47        update_live_params_request = cls(
48            params=params,
49        )
50
51        update_live_params_request.additional_properties = d
52        return update_live_params_request
53
54    @property
55    def additional_keys(self) -> list[str]:
56        return list(self.additional_properties.keys())
57
58    def __getitem__(self, key: str) -> Any:
59        return self.additional_properties[key]
60
61    def __setitem__(self, key: str, value: Any) -> None:
62        self.additional_properties[key] = value
63
64    def __delitem__(self, key: str) -> None:
65        del self.additional_properties[key]
66
67    def __contains__(self, key: str) -> bool:
68        return key in self.additional_properties

Attributes: params (UpdateLiveParamsRequestParams): Must be non-empty; every key must be a property your strategy declares.

UpdateLiveParamsRequest( params: UpdateLiveParamsRequestParams)
24def __init__(self, params):
25    self.params = params
26    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class UpdateLiveParamsRequest.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
27    def to_dict(self) -> dict[str, Any]:
28        params = self.params.to_dict()
29
30        field_dict: dict[str, Any] = {}
31        field_dict.update(self.additional_properties)
32        field_dict.update(
33            {
34                "params": params,
35            }
36        )
37
38        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
40    @classmethod
41    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
42        from ..models.update_live_params_request_params import UpdateLiveParamsRequestParams
43
44        d = dict(src_dict)
45        params = UpdateLiveParamsRequestParams.from_dict(d.pop("params"))
46
47        update_live_params_request = cls(
48            params=params,
49        )
50
51        update_live_params_request.additional_properties = d
52        return update_live_params_request
additional_keys: list[str]
54    @property
55    def additional_keys(self) -> list[str]:
56        return list(self.additional_properties.keys())
class UpdateLiveParamsRequestParams:
13@_attrs_define
14class UpdateLiveParamsRequestParams:
15    """Must be non-empty; every key must be a property your strategy declares."""
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        update_live_params_request_params = cls()
30
31        update_live_params_request_params.additional_properties = d
32        return update_live_params_request_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

Must be non-empty; every key must be a property your strategy declares.

UpdateLiveParamsRequestParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class UpdateLiveParamsRequestParams.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
26    @classmethod
27    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
28        d = dict(src_dict)
29        update_live_params_request_params = cls()
30
31        update_live_params_request_params.additional_properties = d
32        return update_live_params_request_params
additional_keys: list[str]
34    @property
35    def additional_keys(self) -> list[str]:
36        return list(self.additional_properties.keys())
class UpdateLiveRequest:
16@_attrs_define
17class UpdateLiveRequest:
18    """
19    Attributes:
20        visibility (UpdateLiveRequestVisibility | Unset):
21        name (str | Unset):
22        description (str | Unset):
23    """
24
25    visibility: UpdateLiveRequestVisibility | Unset = UNSET
26    name: str | Unset = UNSET
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        visibility: str | Unset = UNSET
32        if not isinstance(self.visibility, Unset):
33            visibility = self.visibility.value
34
35        name = self.name
36
37        description = self.description
38
39        field_dict: dict[str, Any] = {}
40        field_dict.update(self.additional_properties)
41        field_dict.update({})
42        if visibility is not UNSET:
43            field_dict["visibility"] = visibility
44        if name is not UNSET:
45            field_dict["name"] = name
46        if description is not UNSET:
47            field_dict["description"] = description
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        _visibility = d.pop("visibility", UNSET)
55        visibility: UpdateLiveRequestVisibility | Unset
56        if isinstance(_visibility, Unset):
57            visibility = UNSET
58        else:
59            visibility = UpdateLiveRequestVisibility(_visibility)
60
61        name = d.pop("name", UNSET)
62
63        description = d.pop("description", UNSET)
64
65        update_live_request = cls(
66            visibility=visibility,
67            name=name,
68            description=description,
69        )
70
71        update_live_request.additional_properties = d
72        return update_live_request
73
74    @property
75    def additional_keys(self) -> list[str]:
76        return list(self.additional_properties.keys())
77
78    def __getitem__(self, key: str) -> Any:
79        return self.additional_properties[key]
80
81    def __setitem__(self, key: str, value: Any) -> None:
82        self.additional_properties[key] = value
83
84    def __delitem__(self, key: str) -> None:
85        del self.additional_properties[key]
86
87    def __contains__(self, key: str) -> bool:
88        return key in self.additional_properties

Attributes: visibility (UpdateLiveRequestVisibility | Unset): name (str | Unset): description (str | Unset):

UpdateLiveRequest( visibility: UpdateLiveRequestVisibility | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, name: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, description: str | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
26def __init__(self, visibility=attr_dict['visibility'].default, name=attr_dict['name'].default, description=attr_dict['description'].default):
27    self.visibility = visibility
28    self.name = name
29    self.description = description
30    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class UpdateLiveRequest.

visibility: UpdateLiveRequestVisibility | qtsurfer.api.client._generated.types.Unset
name: str | qtsurfer.api.client._generated.types.Unset
description: str | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
30    def to_dict(self) -> dict[str, Any]:
31        visibility: str | Unset = UNSET
32        if not isinstance(self.visibility, Unset):
33            visibility = self.visibility.value
34
35        name = self.name
36
37        description = self.description
38
39        field_dict: dict[str, Any] = {}
40        field_dict.update(self.additional_properties)
41        field_dict.update({})
42        if visibility is not UNSET:
43            field_dict["visibility"] = visibility
44        if name is not UNSET:
45            field_dict["name"] = name
46        if description is not UNSET:
47            field_dict["description"] = description
48
49        return field_dict
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
51    @classmethod
52    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
53        d = dict(src_dict)
54        _visibility = d.pop("visibility", UNSET)
55        visibility: UpdateLiveRequestVisibility | Unset
56        if isinstance(_visibility, Unset):
57            visibility = UNSET
58        else:
59            visibility = UpdateLiveRequestVisibility(_visibility)
60
61        name = d.pop("name", UNSET)
62
63        description = d.pop("description", UNSET)
64
65        update_live_request = cls(
66            visibility=visibility,
67            name=name,
68            description=description,
69        )
70
71        update_live_request.additional_properties = d
72        return update_live_request
additional_keys: list[str]
74    @property
75    def additional_keys(self) -> list[str]:
76        return list(self.additional_properties.keys())
class UpdateLiveRequestVisibility(builtins.str, enum.Enum):
 5class UpdateLiveRequestVisibility(str, Enum):
 6    PRIVATE = "private"
 7    PUBLIC = "public"
 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'.

PRIVATE = <UpdateLiveRequestVisibility.PRIVATE: 'private'>
PUBLIC = <UpdateLiveRequestVisibility.PUBLIC: 'public'>
class WalkForwardAccepted:
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.
WalkForwardAccepted(folds: int, in_sample_pct: int, total_runs: int)
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.

folds: int
in_sample_pct: int
total_runs: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
68    @property
69    def additional_keys(self) -> list[str]:
70        return list(self.additional_properties.keys())
class WalkForwardFold:
 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.
WalkForwardFold( fold_ix: int, in_sample_from: int, in_sample_to: int, out_of_sample_to: int, params: WalkForwardFoldParams, in_sample_sharpe: float, out_of_sample: SweepRunRow, vectors_run: int)
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.

fold_ix: int
in_sample_from: int
in_sample_to: int
out_of_sample_to: int
in_sample_sharpe: float
out_of_sample: SweepRunRow
vectors_run: int
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
115    @property
116    def additional_keys(self) -> list[str]:
117        return list(self.additional_properties.keys())
class WalkForwardFoldParams:
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.

WalkForwardFoldParams()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class WalkForwardFoldParams.

additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
34    @property
35    def additional_keys(self) -> list[str]:
36        return list(self.additional_properties.keys())
class WalkForwardRequest:
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.
WalkForwardRequest( folds: int, in_sample_pct: int | qtsurfer.api.client._generated.types.Unset = 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.

folds: int
in_sample_pct: int | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
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
additional_keys: list[str]
70    @property
71    def additional_keys(self) -> list[str]:
72        return list(self.additional_properties.keys())
class WalkForwardResult:
 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.
WalkForwardResult( folds: int, completed_folds: int, results: list[WalkForwardFold], in_sample_pct: int | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>, param_drift: float | qtsurfer.api.client._generated.types.Unset = <qtsurfer.api.client._generated.types.Unset object>)
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.

folds: int
completed_folds: int
results: list[WalkForwardFold]
in_sample_pct: int | qtsurfer.api.client._generated.types.Unset
param_drift: float | qtsurfer.api.client._generated.types.Unset
additional_properties: dict[str, typing.Any]
def to_dict(self) -> dict[str, typing.Any]:
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
@classmethod
def from_dict(cls: type[~T], src_dict: Mapping[str, typing.Any]) -> ~T:
 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
additional_keys: list[str]
105    @property
106    def additional_keys(self) -> list[str]:
107        return list(self.additional_properties.keys())
ScalarStrategyParamValue: TypeAlias = bool | float | str