Skip to content

Conversation

@guzus
Copy link
Owner

@guzus guzus commented Jan 18, 2026

Summary

Implemented support for Fill-Or-Kill (FOK) and Immediate-Or-Cancel (IOC/FAK) order types.

Changes

  • Added OrderTimeInForce enum with GTC, FOK, and IOC options
  • Updated Order model with time_in_force field
  • Updated Exchange.create_order() to accept time_in_force parameter
  • Implemented support in all exchanges (Polymarket, Opinion, Limitless)
  • Added comprehensive tests

Closes #22

Generated with Claude Code

Repository owner deleted a comment from claude bot Jan 18, 2026
Repository owner deleted a comment from claude bot Jan 18, 2026
Repository owner deleted a comment from claude bot Jan 18, 2026
@claude
Copy link

claude bot commented Jan 18, 2026

PR Review: Add support for FOK and IOC order types

Summary

This PR implements Fill-Or-Kill (FOK) and Immediate-Or-Cancel (IOC) order types across the codebase. The implementation is well-structured and follows the project's patterns. Below is my detailed review.


✅ Strengths

1. Clean API Design

  • The OrderTimeInForce enum is well-designed with clear documentation
  • Default value of GTC maintains backward compatibility
  • Consistent naming following industry standards (GTC, FOK, IOC)

2. Comprehensive Testing

  • Good test coverage in test_models.py for the new enum
  • Tests verify default behavior and explicit time_in_force values
  • Enum value assertions ensure correct string mappings

3. Exchange-Specific Validation

  • Kalshi: Full support for GTC, FOK, and IOC ✓
  • Polymarket: Proper mapping to py_clob_client OrderType ✓
  • Limitless: Correctly validates and rejects IOC (not supported) ✓
  • Opinion: Correctly validates and rejects FOK/IOC (GTC only) ✓

4. Documentation

  • Excellent Kalshi documentation in wiki/exchanges/kalshi.md
  • Clear parameter descriptions in docstrings
  • Follows CLAUDE.md guideline Better MX #6 for exchange documentation

⚠️ Issues Found

1. CRITICAL: PredictFun Missing time_in_force Parameter

Location: dr_manhattan/exchanges/predictfun.py:967

The create_order method signature is missing the time_in_force parameter:

def create_order(
    self,
    market_id: str,
    outcome: str,
    side: OrderSide,
    price: float,
    size: float,
    params: Optional[Dict[str, Any]] = None,
) -> Order:

Expected:

def create_order(
    self,
    market_id: str,
    outcome: str,
    side: OrderSide,
    price: float,
    size: float,
    params: Optional[Dict[str, Any]] = None,
    time_in_force: OrderTimeInForce = OrderTimeInForce.GTC,
) -> Order:

Impact: This breaks the base class contract and will cause issues if time_in_force is passed to PredictFun.

Fix Required: Update the signature and add validation (likely only GTC is supported).

2. POTENTIAL BUG: Polymarket IOC Mapping

Location: dr_manhattan/exchanges/polymarket.py:798

order_type_map = {
    OrderTimeInForce.GTC: OrderType.GTC,
    OrderTimeInForce.FOK: OrderType.FOK,
    OrderTimeInForce.IOC: OrderType.GTD,  # py_clob_client uses GTD for IOC behavior
}

Concern: The comment states "py_clob_client uses GTD for IOC behavior" but this needs verification:

  • Is OrderType.GTD (Good-Till-Date) truly equivalent to IOC?
  • GTD typically requires an expiration timestamp, while IOC should execute immediately
  • This could lead to unexpected behavior or rejected orders

Recommendation:

  • Verify the py_clob_client library documentation
  • If GTD ≠ IOC, either reject IOC orders like Limitless does, or properly implement it
  • Add a comment explaining the technical reasoning if this mapping is correct

3. Missing Order Return Values

Location: dr_manhattan/exchanges/polymarket.py:835 and dr_manhattan/exchanges/opinion.py:656

When creating orders, the time_in_force field is set in the returned Order object, but it's not clear if exchanges actually return this value or if we're just echoing back what was sent.

Potential issue: If an exchange rejects FOK/IOC and falls back to GTC, we'd incorrectly report the order as FOK/IOC.

Recommendation: Parse the actual time_in_force from the exchange response if available.


🔍 Code Quality Observations

Good Practices

  • Proper error messages with exchange-specific constraints
  • Type hints are consistently used
  • Follows existing code patterns

Minor Issues

  1. Inconsistent Error Messages

    • Limitless: "Limitless does not support IOC orders. Use GTC or FOK instead."
    • Opinion: "Opinion does not support {tif} orders. Only GTC orders are supported."
    • Recommend standardizing the format
  2. Documentation Completeness

    • Only Kalshi has wiki documentation; other exchanges should also document their TIF support
    • Consider adding a table in the main README showing which exchanges support which order types

🧪 Test Coverage

What's Covered ✓

  • Enum values and types
  • Default behavior (GTC)
  • Explicit time_in_force assignment

What's Missing ❌

  • Integration tests for actual order placement with different TIF values
  • Validation tests for exchanges rejecting unsupported TIF values (Opinion/Limitless)
  • Edge cases: What happens when FOK can't be filled? Is the order properly rejected?

Recommendation: Add integration tests like:

def test_limitless_rejects_ioc():
    exchange = Limitless({...})
    with pytest.raises(InvalidOrder, match="does not support IOC"):
        exchange.create_order(..., time_in_force=OrderTimeInForce.IOC)

🔒 Security Concerns

No security issues identified. The implementation doesn't introduce new attack vectors.


⚡ Performance Considerations

No performance impact. The changes are additive and don't affect existing code paths.


📋 Recommendations

Must Fix (Blocking)

  1. ✅ Add time_in_force parameter to PredictFun.create_order()
  2. ✅ Verify Polymarket GTD/IOC mapping is correct

Should Fix (High Priority)

  1. Add integration tests for TIF validation
  2. Verify exchanges return correct TIF values in order responses
  3. Add standardized error messages across exchanges

Nice to Have (Low Priority)

  1. Document TIF support for all exchanges in wiki
  2. Add a compatibility matrix in the main README
  3. Consider adding TIF support to the base Exchange.describe() capability dict

🎯 Overall Assessment

Code Quality: 8/10
Test Coverage: 6/10
Documentation: 7/10

This is a solid implementation with good design decisions. The main blocker is the missing PredictFun parameter, and the Polymarket GTD mapping needs verification. Once those are addressed, this PR will be ready to merge.

Great work following the CLAUDE.md guidelines, especially the exchange documentation requirement!

github-actions bot and others added 4 commits January 18, 2026 18:25
- Add OrderTimeInForce enum with GTC, FOK, and IOC options
- Update Order model with time_in_force field (defaults to GTC)
- Update Exchange.create_order() to accept time_in_force parameter
- Implement time_in_force support in all exchanges:
  - Polymarket: Maps to py_clob_client OrderType (GTC, FOK, GTD for IOC)
  - Opinion: Adds parameter support (SDK may have limited support)
  - Limitless: Sends timeInForce in API payload
- Add comprehensive tests for OrderTimeInForce enum
- Export OrderTimeInForce in public API

Closes #22

Co-authored-by: guzus <guzus@users.noreply.github.com>
- Limitless: Only supports GTC and FOK, rejects IOC with InvalidOrder
- Opinion: Only supports GTC, rejects FOK/IOC with InvalidOrder
- Kalshi: Added time_in_force parameter with full GTC/FOK/IOC support
- Polymarket: Already has full GTC/FOK/IOC support (no changes)

This ensures users get clear error messages when using unsupported
order types on exchanges that don't support them.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create wiki/exchanges/kalshi.md with comprehensive API documentation
- Add CLAUDE.md rule requiring wiki docs when integrating new exchanges

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use full string values per Kalshi API spec:
- good_till_canceled (not gtc)
- fill_or_kill (not fok)
- immediate_or_cancel (not ioc)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@guzus guzus force-pushed the claude/issue-22-20251219-1308 branch from c64aeea to cd95290 Compare January 18, 2026 09:26
Repository owner deleted a comment from claude bot Jan 18, 2026
Repository owner deleted a comment from claude bot Jan 18, 2026
@guzus guzus force-pushed the claude/issue-22-20251219-1308 branch from cd95290 to 3718798 Compare January 18, 2026 09:28
- Fix PredictFun.id to return "predict.fun" to match registry key
- Update exchange count in tests from 4 to 5 (Kalshi added)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@guzus guzus force-pushed the claude/issue-22-20251219-1308 branch from 3718798 to 365a19a Compare January 18, 2026 09:28
@claude
Copy link

claude bot commented Jan 18, 2026

Pull Request Review: Add support for FOK and IOC order types

Summary

This PR successfully implements support for Fill-Or-Kill (FOK) and Immediate-Or-Cancel (IOC) order types across the dr-manhattan prediction market SDK. The implementation is well-structured and properly handles exchange-specific capabilities.

Strengths

  1. Clean API Design - The OrderTimeInForce enum is well-defined with clear documentation. Default to GTC maintains backward compatibility.
  2. Exchange-Specific Validation - Each exchange explicitly validates supported time_in_force values with clear error messages.
  3. Documentation - Comprehensive Kalshi wiki documentation (446 lines) and CLAUDE.md updated with exchange documentation requirement.
  4. Test Coverage - Tests for enum values, Order model with time_in_force field, and default behavior.
  5. Proper API Mapping - Kalshi maps to full API strings, Polymarket to py_clob_client OrderType, Limitless uses timeInForce strings.

Critical Issues

1. PredictFun Exchange Missing time_in_force Support

  • Location: dr_manhattan/exchanges/predictfun.py:967-975
  • Issue: create_order() method signature does not include the time_in_force parameter
  • Impact: Breaks base class contract, will cause TypeErrors
  • Fix: Add time_in_force parameter with GTC default and validation

2. Missing time_in_force in Order Creation

  • Location: dr_manhattan/exchanges/limitless.py:709-759
  • Issue: Limitless create_order() does not set time_in_force field on Order objects
  • Fix: Add time_in_force=time_in_force when constructing Order

3. Missing time_in_force in PredictFun Order Objects

  • Location: dr_manhattan/exchanges/predictfun.py:580-591 and 1072-1082
  • Fix: Add time_in_force=OrderTimeInForce.GTC when constructing Order objects

4. Incomplete Import in PredictFun

  • Location: dr_manhattan/exchanges/predictfun.py:31
  • Fix: Add OrderTimeInForce to import statement

Minor Issues

  • Missing integration tests for time_in_force validation errors
  • Polymarket IOC to GTD mapping needs verification (different semantics)

Overall Assessment

Quality: Good (4/5) | Completeness: 85% | Risk: Low

The PR demonstrates good software engineering with clear separation of concerns, proper validation, and comprehensive documentation. Main issues are PredictFun missing time_in_force implementation. Once resolved, ready to merge.


Generated by Claude Code

@claude
Copy link

claude bot commented Jan 18, 2026

PR Review: Add support for FOK and IOC order types

Summary

This PR implements Fill-Or-Kill (FOK) and Immediate-Or-Cancel (IOC) order types across all exchanges. The implementation is solid overall with good documentation and test coverage. Below are my findings.

✅ Strengths

  1. Clean Model Design: The OrderTimeInForce enum is well-structured with clear documentation
  2. Comprehensive Documentation: The new Kalshi wiki documentation is excellent and follows the template
  3. Exchange-Specific Validation: Proper validation for unsupported time-in-force types (Opinion only supports GTC, Limitless doesn't support IOC)
  4. Good Test Coverage: Tests cover all three time-in-force options
  5. Backward Compatibility: Default value of GTC maintains backward compatibility

🐛 Critical Issues

1. Missing time_in_force in Kalshi _parse_order method

Location: dr_manhattan/exchanges/kalshi.py:294

The _parse_order method doesn't set the time_in_force field when parsing orders from API responses. This will cause orders to always show GTC even if they were created with FOK/IOC.

Impact: High - Order objects won't accurately reflect the actual time-in-force setting

Fix needed:

# In _parse_order method, add before return:
tif_str = data.get("time_in_force", "good_till_canceled").lower()
tif_map = {
    "good_till_canceled": OrderTimeInForce.GTC,
    "fill_or_kill": OrderTimeInForce.FOK,
    "immediate_or_cancel": OrderTimeInForce.IOC,
}
time_in_force = tif_map.get(tif_str, OrderTimeInForce.GTC)

# Then add to Order constructor:
time_in_force=time_in_force,

2. Potential IOC mapping issue in Polymarket

Location: dr_manhattan/exchanges/polymarket.py:798

OrderTimeInForce.IOC: OrderType.GTD,  # py_clob_client uses GTD for IOC behavior

Concern: The comment claims GTD provides IOC behavior, but this needs verification. GTD (Good-Til-Date) typically requires an expiration time and may not behave exactly like IOC.

Recommendation:

  • Verify that py_clob_client's GTD actually provides IOC semantics
  • Check if the Polymarket API actually supports IOC or if this is a workaround
  • If GTD doesn't truly match IOC behavior, consider raising InvalidOrder like Limitless and Opinion do for unsupported types

⚠️ Medium Priority Issues

3. Inconsistent error handling in exchange implementations

Some exchanges set time_in_force when creating Order objects, others don't:

  • ✅ Polymarket: Sets it (line 835)
  • ✅ Opinion: Sets it (line 656)
  • ❌ Kalshi: Missing in return statement
  • ❌ Limitless: Not explicitly set in the Order creation (needs verification)

Recommendation: Ensure all exchanges set time_in_force when creating orders.

4. PredictFun exchange ID change

Location: dr_manhattan/exchanges/predictfun.py:119

-        return "predictfun"
+        return "predict.fun"

Concern: This is an unrelated change that could break existing code relying on the old ID. While it may be more correct, it should either:

  • Be in a separate PR with a migration note
  • Be documented as a breaking change
  • Have the old ID maintained for backward compatibility

💡 Minor Suggestions

5. Documentation could mention exchange-specific limitations upfront

The base Exchange.create_order() docstring mentions all three options are available, but doesn't note that support is exchange-specific. Consider adding:

time_in_force: Order time in force (GTC, FOK, IOC). Default is GTC.
    Note: Not all exchanges support all options. Check exchange documentation.
    - GTC (Good-Til-Cancel): Order remains active until filled or cancelled
    - FOK (Fill-Or-Kill): Order must be filled immediately and completely or cancelled
    - IOC (Immediate-Or-Cancel): Fill what's available immediately, cancel the rest

6. Test coverage could include exchange-specific validation

Tests in test_models.py validate the enum and Order model, but integration tests validating that exchanges properly reject unsupported time-in-force types would be valuable.

7. Consider adding a has capability flag

Following CCXT patterns, consider adding to each exchange's describe():

"has": {
    ...
    "time_in_force_gtc": True,
    "time_in_force_fok": True,  # or False
    "time_in_force_ioc": True,  # or False
}

🔒 Security

No security concerns identified. The validation of time-in-force types is appropriate.

🚀 Performance

No performance concerns. The implementation is efficient.

📋 Code Quality

  • Code follows project conventions
  • Adheres to CLAUDE.md guidelines (focused, clean, no emojis)
  • Wiki documentation follows the template (guideline Better MX #6)
  • Good use of type hints and clear variable names

✅ Action Items

Must fix before merge:

  1. Add time_in_force field to Kalshi's _parse_order method
  2. Verify Polymarket's GTD mapping or document the limitation
  3. Either revert PredictFun ID change or document as breaking change

Should fix:
4. Ensure all exchanges set time_in_force when creating Order objects
5. Add integration tests for exchange-specific validation

Nice to have:
6. Update base Exchange docstring to mention exchange-specific support
7. Add capability flags to describe() method

Overall Assessment

Strong implementation with good architecture and documentation. The critical issue with Kalshi's _parse_order must be fixed before merge, but otherwise this is well-executed. The exchange-specific validation is particularly good - better to fail fast with clear errors than silently accept unsupported options.

Recommendation: Request changes for critical issues, then approve once fixed.

@claude
Copy link

claude bot commented Jan 18, 2026

Pull Request Review - PR #64: Add support for FOK and IOC order types

Summary

This PR adds support for Fill-Or-Kill (FOK) and Immediate-Or-Cancel (IOC) order types across the codebase. The implementation is well-structured and includes proper validation, comprehensive tests, and excellent documentation. Overall, this is high-quality work with good attention to detail.


Strengths

1. Clean Architecture

  • The OrderTimeInForce enum is well-defined with clear comments explaining each type
  • Default parameter handling maintains backward compatibility
  • Proper separation of concerns between base class and exchange-specific implementations

2. Exchange-Specific Validation

Excellent work implementing exchange-specific validation:

  • Kalshi: Full GTC/FOK/IOC support with proper API value mapping
  • Polymarket: Full support with correct mapping to py_clob_client.OrderType
  • Limitless: Clear rejection of IOC with helpful error message
  • Opinion: Clear rejection of FOK/IOC with helpful error message

3. Documentation

  • The Kalshi wiki documentation is comprehensive and well-organized
  • Good addition to CLAUDE.md requiring wiki docs for new exchanges
  • Clear inline docstrings explaining the time_in_force parameter

4. Testing

  • Comprehensive unit tests for the new enum
  • Tests cover all three time-in-force types
  • Good coverage of the default behavior

Issues and Concerns

1. CRITICAL: Polymarket IOC Mapping May Be Incorrect

Location: dr_manhattan/exchanges/polymarket.py:798

The code maps IOC to GTD (Good-Til-Date) with a comment claiming GTD provides IOC behavior. This seems unlikely as GTD typically remains active until a specific date/time, while IOC immediately fills what's possible and cancels the rest.

Recommendation: Verify this mapping against the py_clob_client library documentation. If GTD doesn't provide IOC behavior, either raise InvalidOrder for IOC or use the correct OrderType.

2. Missing time_in_force in Order Construction

Recommendation: Verify that all exchange implementations properly set time_in_force in their Order objects, especially in parse_order methods.

3. Test Coverage Gaps

Missing integration tests for:

  • Creating orders with FOK/IOC on exchanges that support it
  • Verifying validation errors are raised for unsupported combinations
  • Testing exchange-specific API value mappings

4. Inconsistent Error Messages

Error messages have different formats across exchanges. Recommend standardizing for consistency.

5. PredictFun Exchange ID Change

Location: dr_manhattan/exchanges/predictfun.py:119

The exchange ID was changed from "predictfun" to "predict.fun". This seems unrelated to the time-in-force feature and could be a breaking change. Either revert this or document it clearly in the PR description.


Suggestions

  • Consider adding a validation helper method to reduce code duplication
  • Update describe() methods to indicate supported time-in-force options
  • Extract hardcoded API values to module-level constants

Security and Performance

Security: No issues detected
Performance: No regressions expected


Code Quality Score: 8/10

  • Architecture: 9/10
  • Code Quality: 8/10
  • Testing: 6/10 (needs integration tests)
  • Documentation: 9/10
  • Error Handling: 8/10

Final Recommendation

Conditional Approval - Please address the critical Polymarket IOC mapping issue before merging. Once verified/fixed and integration tests added, this will be ready to merge.

Great job on the comprehensive documentation and thoughtful exchange-specific validation!

- Add WebSocket authentication details
- Add subscribe/unsubscribe command examples
- Remove See Also section

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 18, 2026

PR Review: Add support for FOK and IOC order types

Summary

This PR successfully implements Fill-Or-Kill (FOK) and Immediate-Or-Cancel (IOC) order types across the dr-manhattan prediction market SDK. The implementation is well-structured and includes proper validation, documentation, and tests.

Code Quality: Good

Strengths

  1. Clean enum design - The OrderTimeInForce enum at dr_manhattan/models/order.py:21 is well-documented with clear descriptions
  2. Consistent API - All exchanges follow the same interface with the time_in_force parameter
  3. Proper defaults - Defaults to GTC which is the safest option
  4. Export handling - Correctly exported in init.py for public API access
  5. Good documentation - The Kalshi wiki documentation is comprehensive and well-structured

Concerns

  1. Polymarket mapping issue - At dr_manhattan/exchanges/polymarket.py:798, IOC is mapped to OrderType.GTD (Good-Till-Date) with a comment saying py_clob_client uses GTD for IOC behavior. This needs verification:

    • Is this actually correct behavior or a workaround?
    • GTD typically requires an expiration time, which is not provided
    • This could cause unexpected behavior or order rejections
    • Recommendation: Verify with Polymarket py_clob_client documentation or add error handling if GTD is not the right mapping
  2. Missing time_in_force persistence - At dr_manhattan/exchanges/kalshi.py:525, when parsing the order response from Kalshi, the time_in_force is not set on the returned Order object. This means:

    • Orders created with FOK/IOC will have their time_in_force reset to the default GTC
    • Users will not be able to see what time_in_force was used for their orders
    • Recommendation: Parse and set time_in_force from the API response, or explicitly preserve the input parameter

Test Coverage: Partial

Good:

  • Unit tests for the enum values (tests/test_models.py:361-365)
  • Unit tests for Order creation with different time_in_force values (tests/test_models.py:367-411)

Missing:

  • No integration tests actually creating orders with FOK/IOC on real exchanges
  • No tests verifying that Opinion/Limitless properly reject unsupported order types
  • No tests for the Polymarket GTD mapping
  • No tests for Kalshi time_in_force API integration

Performance: No concerns

The changes do not introduce any performance issues. Simple enum checks and dictionary lookups are negligible.

Security: Good

  1. Input validation - All exchanges properly validate the time_in_force parameter
  2. Early rejection - Unsupported order types are rejected before making API calls (good for rate limiting)
  3. No injection risks - Values are mapped through controlled dictionaries, not concatenated

Best Practices: Minor issues

  1. Inconsistent error messages - Limitless and Opinion use different error message formats. Recommendation: Standardize to always include which types ARE supported

  2. Mixed use of .get() with default - At dr_manhattan/exchanges/kalshi.py:514, the fallback is unnecessary since all enum values are in the map. This could silently hide bugs if an invalid value is passed.

  3. PredictFun ID change - At dr_manhattan/exchanges/predictfun.py:119, the ID was changed from predictfun to predict.fun. While this might be correct, it is a breaking change that should be mentioned in the PR description or handled with backwards compatibility if users rely on the old ID

Recommendations Summary

Critical:

  • Verify Polymarket IOC to GTD mapping is correct

High Priority:

  • Preserve time_in_force in Kalshi returned Order objects
  • Add integration tests for error cases (Opinion/Limitless rejections)

Nice to Have:

  • Standardize error messages across exchanges
  • Document the PredictFun ID change as a breaking change
  • Add integration tests for actual FOK/IOC order placement

Overall Assessment: Approve with recommendations

This is a solid implementation that adds valuable functionality. The concerns are relatively minor and mostly around edge cases and testing. The code follows the repository conventions and includes good documentation.

Suggested action: Address the Polymarket GTD mapping concern before merging, as it could cause runtime issues for users.

@guzus guzus merged commit e613837 into main Jan 18, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support FOK / FAK order

2 participants