Skip to main content

nautilus_betfair/python/
config.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Python bindings for Betfair configuration.
17
18use nautilus_model::identifiers::AccountId;
19use pyo3::prelude::*;
20use rust_decimal::Decimal;
21
22use crate::config::{BetfairDataClientConfig, BetfairExecutionClientConfig};
23
24fn stringify_ids(values: Option<Vec<u64>>) -> Option<Vec<String>> {
25    values.map(|values| values.into_iter().map(|value| value.to_string()).collect())
26}
27
28#[pymethods]
29#[pyo3_stub_gen::derive::gen_stub_pymethods]
30impl BetfairDataClientConfig {
31    /// Configuration for the Betfair live data client.
32    #[new]
33    #[pyo3(signature = (
34        account_currency = None,
35        username = None,
36        password = None,
37        app_key = None,
38        proxy_url = None,
39        request_rate_per_second = 5,
40        default_min_notional = None,
41        event_type_ids = None,
42        event_type_names = None,
43        event_ids = None,
44        country_codes = None,
45        market_types = None,
46        market_ids = None,
47        min_market_start_time = None,
48        max_market_start_time = None,
49        stream_host = None,
50        stream_port = None,
51        stream_heartbeat_secs = None,
52        stream_heartbeat_timeout_secs = None,
53        stream_reconnect_delay_initial_ms = 2_000,
54        stream_reconnect_delay_max_ms = 30_000,
55        stream_use_tls = true,
56        stream_conflate_ms = None,
57        subscription_delay_secs = None,
58        subscribe_race_data = false,
59        subscribe_cricket_data = false,
60    ))]
61    #[expect(clippy::too_many_arguments)]
62    fn py_new(
63        account_currency: Option<String>,
64        username: Option<String>,
65        password: Option<String>,
66        app_key: Option<String>,
67        proxy_url: Option<String>,
68        request_rate_per_second: u32,
69        default_min_notional: Option<Decimal>,
70        event_type_ids: Option<Vec<u64>>,
71        event_type_names: Option<Vec<String>>,
72        event_ids: Option<Vec<u64>>,
73        country_codes: Option<Vec<String>>,
74        market_types: Option<Vec<String>>,
75        market_ids: Option<Vec<String>>,
76        min_market_start_time: Option<String>,
77        max_market_start_time: Option<String>,
78        stream_host: Option<String>,
79        stream_port: Option<u16>,
80        stream_heartbeat_secs: Option<u64>,
81        stream_heartbeat_timeout_secs: Option<u64>,
82        stream_reconnect_delay_initial_ms: u64,
83        stream_reconnect_delay_max_ms: u64,
84        stream_use_tls: bool,
85        stream_conflate_ms: Option<u64>,
86        subscription_delay_secs: Option<u64>,
87        subscribe_race_data: bool,
88        subscribe_cricket_data: bool,
89    ) -> Self {
90        Self {
91            account_currency: account_currency.unwrap_or_else(|| "GBP".to_string()),
92            username,
93            password,
94            app_key,
95            proxy_url,
96            request_rate_per_second,
97            default_min_notional,
98            event_type_ids: stringify_ids(event_type_ids),
99            event_type_names,
100            event_ids: stringify_ids(event_ids),
101            country_codes,
102            market_types,
103            market_ids,
104            min_market_start_time,
105            max_market_start_time,
106            stream_host,
107            stream_port,
108            stream_heartbeat_secs,
109            stream_heartbeat_timeout_secs,
110            stream_reconnect_delay_initial_ms,
111            stream_reconnect_delay_max_ms,
112            stream_use_tls,
113            stream_conflate_ms,
114            subscription_delay_secs: subscription_delay_secs.unwrap_or(3),
115            subscribe_race_data,
116            subscribe_cricket_data,
117        }
118    }
119
120    #[getter]
121    const fn has_proxy_url(&self) -> bool {
122        self.proxy_url.is_some()
123    }
124
125    fn __repr__(&self) -> String {
126        stringify!(BetfairDataClientConfig).to_string()
127    }
128}
129
130#[pymethods]
131#[pyo3_stub_gen::derive::gen_stub_pymethods]
132impl BetfairExecutionClientConfig {
133    /// Configuration for the Betfair live execution client.
134    #[new]
135    #[pyo3(signature = (
136        account_id = None,
137        account_currency = None,
138        username = None,
139        password = None,
140        app_key = None,
141        proxy_url = None,
142        request_rate_per_second = 5,
143        order_request_rate_per_second = 20,
144        stream_host = None,
145        stream_port = None,
146        stream_heartbeat_secs = None,
147        stream_heartbeat_timeout_secs = None,
148        stream_reconnect_delay_initial_ms = 2_000,
149        stream_reconnect_delay_max_ms = 30_000,
150        stream_use_tls = true,
151        stream_market_ids_filter = None,
152        ignore_external_orders = false,
153        calculate_account_state = true,
154        request_account_state_secs = 300,
155        reconcile_market_ids_only = false,
156        reconcile_market_ids = None,
157        use_market_version = false,
158        stream_gap_recovery_lookback_mins = 10,
159    ))]
160    #[expect(clippy::too_many_arguments)]
161    fn py_new(
162        account_id: Option<AccountId>,
163        account_currency: Option<String>,
164        username: Option<String>,
165        password: Option<String>,
166        app_key: Option<String>,
167        proxy_url: Option<String>,
168        request_rate_per_second: u32,
169        order_request_rate_per_second: u32,
170        stream_host: Option<String>,
171        stream_port: Option<u16>,
172        stream_heartbeat_secs: Option<u64>,
173        stream_heartbeat_timeout_secs: Option<u64>,
174        stream_reconnect_delay_initial_ms: u64,
175        stream_reconnect_delay_max_ms: u64,
176        stream_use_tls: bool,
177        stream_market_ids_filter: Option<Vec<String>>,
178        ignore_external_orders: bool,
179        calculate_account_state: bool,
180        request_account_state_secs: u64,
181        reconcile_market_ids_only: bool,
182        reconcile_market_ids: Option<Vec<String>>,
183        use_market_version: bool,
184        stream_gap_recovery_lookback_mins: u64,
185    ) -> Self {
186        Self {
187            account_id: account_id.unwrap_or_else(|| AccountId::from("BETFAIR-001")),
188            account_currency: account_currency.unwrap_or_else(|| "GBP".to_string()),
189            username,
190            password,
191            app_key,
192            proxy_url,
193            request_rate_per_second,
194            order_request_rate_per_second,
195            stream_host,
196            stream_port,
197            stream_heartbeat_secs,
198            stream_heartbeat_timeout_secs,
199            stream_reconnect_delay_initial_ms,
200            stream_reconnect_delay_max_ms,
201            stream_use_tls,
202            stream_market_ids_filter,
203            ignore_external_orders,
204            calculate_account_state,
205            request_account_state_secs,
206            reconcile_market_ids_only,
207            reconcile_market_ids,
208            use_market_version,
209            stream_gap_recovery_lookback_mins,
210        }
211    }
212
213    #[getter]
214    const fn has_proxy_url(&self) -> bool {
215        self.proxy_url.is_some()
216    }
217
218    fn __repr__(&self) -> String {
219        stringify!(BetfairExecutionClientConfig).to_string()
220    }
221}