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_core::string::secret::SecretString;
19use nautilus_model::identifiers::AccountId;
20use pyo3::prelude::*;
21use rust_decimal::Decimal;
22
23use crate::config::{BetfairDataClientConfig, BetfairExecutionClientConfig};
24
25fn stringify_ids(values: Option<Vec<u64>>) -> Option<Vec<String>> {
26    values.map(|values| values.into_iter().map(|value| value.to_string()).collect())
27}
28
29#[pymethods]
30#[pyo3_stub_gen::derive::gen_stub_pymethods]
31impl BetfairDataClientConfig {
32    /// Configuration for the Betfair live data client.
33    #[new]
34    #[pyo3(signature = (
35        account_currency = None,
36        username = None,
37        password = None,
38        app_key = None,
39        proxy_url = None,
40        request_rate_per_second = 5,
41        default_min_notional = None,
42        event_type_ids = None,
43        event_type_names = None,
44        event_ids = None,
45        country_codes = None,
46        market_types = None,
47        market_ids = None,
48        min_market_start_time = None,
49        max_market_start_time = None,
50        stream_host = None,
51        stream_port = None,
52        stream_heartbeat_secs = None,
53        stream_heartbeat_timeout_secs = None,
54        stream_reconnect_delay_initial_ms = 2_000,
55        stream_reconnect_delay_max_ms = 30_000,
56        stream_use_tls = true,
57        stream_conflate_ms = None,
58        subscription_delay_secs = None,
59        subscribe_race_data = false,
60        subscribe_cricket_data = false,
61    ))]
62    #[expect(clippy::too_many_arguments)]
63    fn py_new(
64        account_currency: Option<String>,
65        username: Option<String>,
66        password: Option<String>,
67        app_key: Option<String>,
68        proxy_url: Option<String>,
69        request_rate_per_second: u32,
70        default_min_notional: Option<Decimal>,
71        event_type_ids: Option<Vec<u64>>,
72        event_type_names: Option<Vec<String>>,
73        event_ids: Option<Vec<u64>>,
74        country_codes: Option<Vec<String>>,
75        market_types: Option<Vec<String>>,
76        market_ids: Option<Vec<String>>,
77        min_market_start_time: Option<String>,
78        max_market_start_time: Option<String>,
79        stream_host: Option<String>,
80        stream_port: Option<u16>,
81        stream_heartbeat_secs: Option<u64>,
82        stream_heartbeat_timeout_secs: Option<u64>,
83        stream_reconnect_delay_initial_ms: u64,
84        stream_reconnect_delay_max_ms: u64,
85        stream_use_tls: bool,
86        stream_conflate_ms: Option<u64>,
87        subscription_delay_secs: Option<u64>,
88        subscribe_race_data: bool,
89        subscribe_cricket_data: bool,
90    ) -> Self {
91        Self {
92            account_currency: account_currency.unwrap_or_else(|| "GBP".to_string()),
93            username: username.map(SecretString::from),
94            password: password.map(SecretString::from),
95            app_key: app_key.map(SecretString::from),
96            proxy_url: proxy_url.map(SecretString::from),
97            request_rate_per_second,
98            default_min_notional,
99            event_type_ids: stringify_ids(event_type_ids),
100            event_type_names,
101            event_ids: stringify_ids(event_ids),
102            country_codes,
103            market_types,
104            market_ids,
105            min_market_start_time,
106            max_market_start_time,
107            stream_host,
108            stream_port,
109            stream_heartbeat_secs,
110            stream_heartbeat_timeout_secs,
111            stream_reconnect_delay_initial_ms,
112            stream_reconnect_delay_max_ms,
113            stream_use_tls,
114            stream_conflate_ms,
115            subscription_delay_secs: subscription_delay_secs.unwrap_or(3),
116            subscribe_race_data,
117            subscribe_cricket_data,
118        }
119    }
120
121    /// Returns the username.
122    #[getter]
123    fn username(&self) -> Option<&str> {
124        self.username.as_ref().map(SecretString::expose_secret)
125    }
126
127    #[getter]
128    const fn has_proxy_url(&self) -> bool {
129        self.proxy_url.is_some()
130    }
131
132    fn __repr__(&self) -> String {
133        stringify!(BetfairDataClientConfig).to_string()
134    }
135}
136
137#[pymethods]
138#[pyo3_stub_gen::derive::gen_stub_pymethods]
139impl BetfairExecutionClientConfig {
140    /// Configuration for the Betfair live execution client.
141    #[new]
142    #[pyo3(signature = (
143        account_id = None,
144        account_currency = None,
145        username = None,
146        password = None,
147        app_key = None,
148        proxy_url = None,
149        request_rate_per_second = 5,
150        order_request_rate_per_second = 20,
151        stream_host = None,
152        stream_port = None,
153        stream_heartbeat_secs = None,
154        stream_heartbeat_timeout_secs = None,
155        stream_reconnect_delay_initial_ms = 2_000,
156        stream_reconnect_delay_max_ms = 30_000,
157        stream_use_tls = true,
158        stream_market_ids_filter = None,
159        ignore_external_orders = false,
160        calculate_account_state = true,
161        request_account_state_secs = 300,
162        reconcile_market_ids_only = false,
163        reconcile_market_ids = None,
164        use_market_version = false,
165        stream_gap_recovery_lookback_mins = 10,
166    ))]
167    #[expect(clippy::too_many_arguments)]
168    fn py_new(
169        account_id: Option<AccountId>,
170        account_currency: Option<String>,
171        username: Option<String>,
172        password: Option<String>,
173        app_key: Option<String>,
174        proxy_url: Option<String>,
175        request_rate_per_second: u32,
176        order_request_rate_per_second: u32,
177        stream_host: Option<String>,
178        stream_port: Option<u16>,
179        stream_heartbeat_secs: Option<u64>,
180        stream_heartbeat_timeout_secs: Option<u64>,
181        stream_reconnect_delay_initial_ms: u64,
182        stream_reconnect_delay_max_ms: u64,
183        stream_use_tls: bool,
184        stream_market_ids_filter: Option<Vec<String>>,
185        ignore_external_orders: bool,
186        calculate_account_state: bool,
187        request_account_state_secs: u64,
188        reconcile_market_ids_only: bool,
189        reconcile_market_ids: Option<Vec<String>>,
190        use_market_version: bool,
191        stream_gap_recovery_lookback_mins: u64,
192    ) -> Self {
193        Self {
194            account_id: account_id.unwrap_or_else(|| AccountId::from("BETFAIR-001")),
195            account_currency: account_currency.unwrap_or_else(|| "GBP".to_string()),
196            username: username.map(SecretString::from),
197            password: password.map(SecretString::from),
198            app_key: app_key.map(SecretString::from),
199            proxy_url: proxy_url.map(SecretString::from),
200            request_rate_per_second,
201            order_request_rate_per_second,
202            stream_host,
203            stream_port,
204            stream_heartbeat_secs,
205            stream_heartbeat_timeout_secs,
206            stream_reconnect_delay_initial_ms,
207            stream_reconnect_delay_max_ms,
208            stream_use_tls,
209            stream_market_ids_filter,
210            ignore_external_orders,
211            calculate_account_state,
212            request_account_state_secs,
213            reconcile_market_ids_only,
214            reconcile_market_ids,
215            use_market_version,
216            stream_gap_recovery_lookback_mins,
217        }
218    }
219
220    /// Returns the username.
221    #[getter]
222    fn username(&self) -> Option<&str> {
223        self.username.as_ref().map(SecretString::expose_secret)
224    }
225
226    #[getter]
227    const fn has_proxy_url(&self) -> bool {
228        self.proxy_url.is_some()
229    }
230
231    fn __repr__(&self) -> String {
232        stringify!(BetfairExecutionClientConfig).to_string()
233    }
234}