Skip to main content

nautilus_polymarket/python/
sort.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 wrappers for Polymarket trade-parsing helpers.
17
18use pyo3::{prelude::*, types::PyDict};
19
20use crate::http::data_api::build_polymarket_trade_id;
21
22/// Returns a deterministic sort key tuple for a Polymarket Data API trade dict.
23///
24/// The Polymarket Data API timestamps are second-resolution and the public
25/// endpoint does not guarantee a stable order across pages. Pass this as the
26/// `key` argument to `list.sort` so concatenated pages produce a deterministic
27/// chronological stream.
28///
29/// The returned tuple is `(timestamp, transactionHash, asset, side, price, size)`,
30/// with all string-typed fields stringified to match Python's behaviour for
31/// dictionaries with mixed-type values. Missing keys default to empty strings,
32/// matching `dict.get(key, "")`.
33#[pyfunction]
34#[pyo3(name = "polymarket_trade_sort_key")]
35pub fn py_polymarket_trade_sort_key(
36    trade: &Bound<'_, PyDict>,
37) -> PyResult<(i64, String, String, String, String, String)> {
38    fn extract_string(trade: &Bound<'_, PyDict>, key: &str) -> PyResult<String> {
39        match trade.get_item(key)? {
40            Some(value) => Ok(value.str()?.extract::<String>()?),
41            None => Ok(String::new()),
42        }
43    }
44
45    let timestamp: i64 = match trade.get_item("timestamp")? {
46        Some(value) => value.extract()?,
47        None => 0,
48    };
49    let transaction_hash = extract_string(trade, "transactionHash")?;
50    let asset = extract_string(trade, "asset")?;
51    let side = extract_string(trade, "side")?;
52    let price = extract_string(trade, "price")?;
53    let size = extract_string(trade, "size")?;
54
55    Ok((timestamp, transaction_hash, asset, side, price, size))
56}
57
58/// Returns the composite Polymarket TradeId for a fill.
59///
60/// Polygon transactions can settle multiple fills sharing the same
61/// `transactionHash`. Using only the last 36 chars collapses them to a single
62/// TradeId and downstream catalog readers silently drop duplicates. The id
63/// composes a hash suffix, an asset suffix, and a per-(tx, asset) sequence so
64/// every fill is preserved.
65#[pyfunction]
66#[pyo3(name = "polymarket_trade_id")]
67pub fn py_polymarket_trade_id(transaction_hash: &str, asset: &str, seq: u32) -> String {
68    build_polymarket_trade_id(transaction_hash, asset, seq)
69}