Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 14, 2025

📄 66% (0.66x) speedup for bitmart.parse_margin_loan in python/ccxt/async_support/bitmart.py

⏱️ Runtime : 565 microseconds 340 microseconds (best of 17 runs)

📝 Explanation and details

The optimization delivers a 66% speedup by eliminating function call overhead in two critical hot paths identified through profiling.

Key Optimizations Applied:

  1. safe_string_2 Function Call Elimination: The original version used Exchange.safe_either(Exchange.safe_string, ...) which involved multiple function calls and method lookups. The optimized version inlines this logic with direct dictionary access and null checks, reducing the per-hit time from 2339ns to 226ns (90% faster per call).

  2. safe_currency_code Fast Path: Added an early return for the common case where currencyId is None and currency is already a dict with a 'code' key. This avoids calling self.safe_currency() in 517 out of 525 calls (98.5% hit rate), reducing per-hit time from 839ns to 340ns.

Performance Impact by Test Case:

  • Simple dictionary lookups see 50-100% speedups (most test cases)
  • Cases with missing keys benefit most (103% speedup in test_parse_missing_ids)
  • Large-scale operations show consistent 75% improvements across 500 iterations
  • Edge cases with None values still see 8-13% gains

Why This Matters:
The parse_margin_loan method is likely called frequently in trading workflows for processing margin loan data. The optimizations target the two most expensive operations (51.9% and 35.5% of original runtime) with zero behavioral changes, making this a pure performance win with no risk of breaking existing functionality.

The fast-path optimizations are particularly effective because they handle the most common usage patterns (valid dictionaries with expected keys) while preserving all original error handling and edge case behavior.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 565 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import pytest
from ccxt.async_support.bitmart import bitmart

# --- function to test (minimal, self-contained version for testing purposes) ---

class DummyExchange:
    # Simulate the safe_string_2 method from ccxt Exchange
    @staticmethod
    def safe_string(dictionary, key, default_value=None):
        return str(dictionary[key]) if key in dictionary and dictionary[key] is not None else default_value

    @classmethod
    def safe_string_2(cls, dictionary, key1, key2, default_value=None):
        value = cls.safe_string(dictionary, key1)
        return value if value is not None else cls.safe_string(dictionary, key2, default_value)

    # Simulate safe_currency_code (returns currency['code'] if currency is not None)
    @staticmethod
    def safe_currency_code(currency_id, currency):
        if currency is None:
            return None
        if isinstance(currency, dict) and 'code' in currency:
            return currency['code']
        return str(currency)

    def parse_margin_loan(self, info, currency=None):
        return {
            'id': self.safe_string_2(info, 'borrow_id', 'repay_id'),
            'currency': self.safe_currency_code(None, currency),
            'amount': None,
            'symbol': None,
            'timestamp': None,
            'datetime': None,
            'info': info,
        }
from ccxt.async_support.bitmart import bitmart

# Basic Test Cases























import pytest
from ccxt.async_support.bitmart import bitmart


# minimal stub for Currency type
class Currency(dict):
    pass
from ccxt.async_support.bitmart import bitmart

# -------------------- UNIT TESTS --------------------

@pytest.fixture
def exchange():
    return bitmart()

# 1. BASIC TEST CASES

def test_parse_borrow_margin(exchange):
    # Basic borrowMargin response
    info = {"borrow_id": "abc123"}
    currency = {'code': 'BTC'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.21μs -> 2.72μs (54.6% faster)

def test_parse_repay_margin(exchange):
    # Basic repayMargin response
    info = {"repay_id": "xyz789"}
    currency = {'code': 'USDT'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.88μs -> 2.57μs (89.9% faster)

def test_parse_both_ids_present(exchange):
    # Both borrow_id and repay_id present: borrow_id should take precedence
    info = {"borrow_id": "b1", "repay_id": "r1"}
    currency = {'code': 'ETH'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.08μs -> 2.49μs (64.2% faster)

def test_parse_no_currency(exchange):
    # No currency provided, should return None for 'currency'
    info = {"borrow_id": "b1"}
    codeflash_output = exchange.parse_margin_loan(info); result = codeflash_output # 10.8μs -> 9.79μs (9.75% faster)

def test_parse_currency_as_currency_class(exchange):
    # Currency passed as a Currency class instance
    info = {"repay_id": "r2"}
    currency = Currency({'code': 'LTC'})
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 5.00μs -> 3.63μs (37.9% faster)

def test_parse_info_unmodified(exchange):
    # The 'info' field in the result should be the same object as input
    info = {"borrow_id": "orig"}
    codeflash_output = exchange.parse_margin_loan(info); result = codeflash_output # 11.0μs -> 9.74μs (12.6% faster)

# 2. EDGE TEST CASES

def test_parse_missing_ids(exchange):
    # Info dict missing both borrow_id and repay_id
    info = {"foo": "bar"}
    currency = {'code': 'DOGE'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.67μs -> 2.30μs (103% faster)

def test_parse_id_is_none(exchange):
    # Info dict with borrow_id=None
    info = {"borrow_id": None}
    currency = {'code': 'ADA'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.66μs -> 2.31μs (102% faster)

def test_parse_id_is_integer(exchange):
    # Info dict with id as integer (should be stringified)
    info = {"borrow_id": 12345}
    currency = {'code': 'BNB'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.38μs -> 2.79μs (56.8% faster)

def test_parse_id_is_float(exchange):
    # Info dict with id as float (should be stringified)
    info = {"repay_id": 12.34}
    currency = {'code': 'XRP'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 7.35μs -> 5.36μs (37.3% faster)


def test_parse_empty_info(exchange):
    # Info dict is empty
    info = {}
    currency = {'code': 'MATIC'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.87μs -> 2.51μs (94.1% faster)

def test_parse_info_is_none(exchange):
    # Info is None (should not crash, but info field should be None)
    info = None
    currency = {'code': 'UNI'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 3.44μs -> 2.27μs (51.7% faster)

def test_parse_currency_is_none(exchange):
    # Currency is None
    info = {"borrow_id": "b2"}
    codeflash_output = exchange.parse_margin_loan(info, None); result = codeflash_output # 10.6μs -> 9.33μs (13.8% faster)


def test_parse_info_extra_fields(exchange):
    # Info dict has extra unrelated fields
    info = {"borrow_id": "b3", "foo": "bar", "baz": 42}
    currency = {'code': 'AVAX'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.01μs -> 2.64μs (52.1% faster)


def test_parse_currency_code_is_none(exchange):
    # Currency dict with code=None
    info = {"borrow_id": "b5"}
    currency = {'code': None}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.24μs -> 2.69μs (57.9% faster)

# 3. LARGE SCALE TEST CASES

def test_parse_many_margin_loans(exchange):
    # Parse a large number of margin loans (performance/scalability)
    loans = []
    for i in range(500):  # Keep under 1000 as per instructions
        info = {"borrow_id": f"id_{i}"}
        currency = {'code': f"CUR{i}"}
        codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 445μs -> 253μs (75.6% faster)
        loans.append(result)
    # Check all ids and currencies are unique and correct
    ids = set(l['id'] for l in loans)
    currencies = set(l['currency'] for l in loans)

def test_parse_large_info_dict(exchange):
    # Info dict with many unrelated keys (should still parse id correctly)
    info = {f"key_{i}": i for i in range(500)}
    info['repay_id'] = "large_id"
    currency = {'code': 'BIG'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 5.00μs -> 2.75μs (81.6% faster)

def test_parse_large_currency_dict(exchange):
    # Currency dict with many keys, only 'code' matters
    info = {"borrow_id": "b6"}
    currency = {f"field_{i}": i for i in range(500)}
    currency['code'] = 'LARGE'
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.11μs -> 2.74μs (49.9% faster)

def test_parse_all_none(exchange):
    # Both info and currency are None
    codeflash_output = exchange.parse_margin_loan(None, None); result = codeflash_output # 10.2μs -> 9.39μs (8.46% faster)

def test_parse_loan_id_is_zero(exchange):
    # Edge case: id is 0 (should be stringified to "0")
    info = {"borrow_id": 0}
    currency = {'code': 'ZERO'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.09μs -> 2.67μs (53.5% faster)


def test_parse_info_with_unicode(exchange):
    # Info dict with unicode id
    info = {"borrow_id": "借款123"}
    currency = {'code': 'CNY'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.20μs -> 2.62μs (60.6% faster)

def test_parse_currency_with_unicode(exchange):
    # Currency code is unicode
    info = {"borrow_id": "b8"}
    currency = {'code': '₿'}
    codeflash_output = exchange.parse_margin_loan(info, currency); result = codeflash_output # 4.05μs -> 2.68μs (51.3% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-bitmart.parse_margin_loan-mhzc10eh and push.

Codeflash

The optimization delivers a **66% speedup** by eliminating function call overhead in two critical hot paths identified through profiling.

**Key Optimizations Applied:**

1. **`safe_string_2` Function Call Elimination**: The original version used `Exchange.safe_either(Exchange.safe_string, ...)` which involved multiple function calls and method lookups. The optimized version inlines this logic with direct dictionary access and null checks, reducing the per-hit time from 2339ns to 226ns (90% faster per call).

2. **`safe_currency_code` Fast Path**: Added an early return for the common case where `currencyId` is `None` and `currency` is already a dict with a `'code'` key. This avoids calling `self.safe_currency()` in 517 out of 525 calls (98.5% hit rate), reducing per-hit time from 839ns to 340ns.

**Performance Impact by Test Case:**
- Simple dictionary lookups see 50-100% speedups (most test cases)
- Cases with missing keys benefit most (103% speedup in `test_parse_missing_ids`)
- Large-scale operations show consistent 75% improvements across 500 iterations
- Edge cases with `None` values still see 8-13% gains

**Why This Matters:**
The `parse_margin_loan` method is likely called frequently in trading workflows for processing margin loan data. The optimizations target the two most expensive operations (51.9% and 35.5% of original runtime) with zero behavioral changes, making this a pure performance win with no risk of breaking existing functionality.

The fast-path optimizations are particularly effective because they handle the most common usage patterns (valid dictionaries with expected keys) while preserving all original error handling and edge case behavior.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 14, 2025 20:50
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Nov 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant