# CLI Source: https://docs.qfex.com/api-reference/cli Use the QFEX CLI for agentic trading and JSON-native command-line workflows. The [QFEX CLI](https://github.com/QFEX-org/cli) provides JSON-only command-line access to QFEX for both human operators and AI agents. It is designed for agentic trading workflows where you want a stateless command interface, while a background daemon manages the underlying WebSocket connections to QFEX. ## Installation ```sh theme={null} brew install QFEX-org/tap/qfex ``` ## AI Agent Setup Run this once to configure QFEX CLI for agent workflows: ```sh theme={null} # Global setup for Claude Code and Codex qfex agents init # Project-local setup for the current directory qfex agents init --local ``` `qfex agents init` updates Claude Code and Codex so `qfex` can be used without repeated permission prompts. The global setup writes to `~/.claude/` and `~/.codex/`. The `--local` mode writes `CLAUDE.md` and `AGENTS.md` into the current project, which is useful when you want project-specific agent instructions. ## Quick Start ```sh theme={null} # Start the background daemon qfex daemon start # Query market data (no credentials required) qfex market bbo AAPL-USD # Log in to trade or access account data qfex login qfex daemon restart # Place an order qfex order place --symbol AAPL-USD --side BUY --type LIMIT --tif GTC --qty 1 --price 200 # Stop the daemon when finished qfex daemon stop ``` ## Why Use The CLI * Built for both humans and AI agents. * All command output is JSON, which makes it easy to pipe into `jq` or parse in code. * The daemon keeps persistent connections to market data and trade WebSockets, so your scripts do not need to manage subscriptions, authentication, or socket lifecycle directly. * Market data commands work without credentials. * Trading commands use the same API keys described in the [API introduction](/api-reference/introduction). ## Agentic Trading Workflow For an automated or agentic trading setup, the normal flow is: 1. Run `qfex agents init` once so your agent can call `qfex` cleanly. 2. Start the daemon with `qfex daemon start`. 3. Use market data commands immediately, or generate API keys and run `qfex login` for trading. 4. Run `qfex daemon restart` after login so credentials are applied. 5. Confirm readiness with `qfex daemon status`. 6. Issue market data, order, position, and account commands as needed. The daemon must be running before most CLI commands will work. ## Common Commands ```sh theme={null} # Market data qfex market bbo AAPL-USD qfex market orderbook AAPL-USD --depth 5 qfex market trades AAPL-USD --limit 50 # Orders qfex order place --symbol AAPL-USD --side BUY --type MARKET --tif IOC --qty 1 qfex order list qfex order cancel --symbol AAPL-USD --order-id # Positions and account state qfex position list qfex account balance qfex account leverage get # Live streams qfex watch bbo AAPL-USD qfex watch orders qfex watch fills ``` ## Environments The CLI supports both QFEX production and UAT environments: * `prod`: Connects to `qfex.com` with real funds. * `uat`: Connects to `qfex.io` for testing strategies and integrations without real funds. You can select the environment during `qfex login` or by editing `~/.config/qfex/config.yaml`, then restarting the daemon. ## Subaccounts If your account has subaccounts, `qfex login` will prompt you to choose which account should be active by default. The selected value is stored in `~/.config/qfex/config.yaml` as `selected_subaccount`. Use these commands to inspect or change it later: ```sh theme={null} qfex account subaccounts current qfex account subaccounts select qfex account subaccounts list ``` Selecting a different subaccount updates the config and restarts the daemon so authenticated trading and account requests use the **new account** context. You can also transfer money very easily, between subaccounts using the following command ```sh theme={null} qfex account subaccounts transfer ``` This command accepts `--from`, `--to`, and `--amount` (in USD). You can set either `--from` or `--to` to `"primary"` to refer to your main account. The other account should be a UUID returned by `qfex account subaccounts list`. ## Links * [QFEX CLI repository](https://github.com/QFEX-org/cli) * [API key setup instructions](/api-reference/introduction) * [WebSocket overview](/websocket/main) # Enums Source: https://docs.qfex.com/api-reference/enums ## OrderType This defines how the order is executed by the engine. The WebSocket API uses the string names below; the numeric values are the corresponding internal values. | Name | Value | Accepted by `add_order` | Description | | ------------- | ----- | ----------------------- | ----------------------------------------------------------------------------------------------------- | | `LIMIT` | 0 | Yes | Limit order. | | `MARKET` | 1 | Yes | Market order. | | `ALO` | 3 | Yes | Add Liquidity Only order. If it would cross the book, the order is rejected. | | `TAKE_PROFIT` | 4 | Yes | Take-profit stop order. | | `STOP_LOSS` | 5 | Yes | Stop-loss stop order. | | `STOP_MARKET` | 6 | No | Market order generated when a stop order triggers; it may appear in order, fill, and trade responses. | | `TWAP_LIMIT` | 7 | No | System-generated child order for a TWAP; it may appear in order, fill, and trade responses. | Internal value `2` is reserved for liquidation orders and is not accepted as a client-facing `OrderType`. ## OrderDirection This defines the direction of the order. | Name | Value | Description | | ------ | ----- | ----------- | | `BUY` | 0 | Buy order | | `SELL` | 1 | Sell order | ## OrderTimeInForce This defines the time in force of the order. | Name | Description | | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `GTC` | Good till canceled. This order will stay in the book until it is filled or canceled. | | `IOC` | Immediate or cancel. This order will fill as much as possible and then be canceled. If the order cannot be filled immediately, the remaining quantity will be canceled. | | `FOK` | Fill or kill. This order will be canceled if it cannot be filled immediately. If the order cannot be filled immediately, the entire order will be canceled. | ## OrderStatus This is returned on any order response. This will indicate the current status of the order. | Name | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `ACK` | Order accepted. | | `IOC_CANCELLED` | The unfilled portion of an immediate-or-cancel order was cancelled. | | `INVALID_PRICE` | Invalid price. | | `INVALID_QUANTITY` | Invalid quantity. | | `NOT_FOUND` | Requested order was not found. | | `IOC_PARTIALLY_FILLED` | Immediate-or-cancel order was partially filled and the remainder cancelled. | | `USER_NOT_FOUND` | User was not found. | | `PERMISSION_DENIED` | User is not permitted to perform this action. | | `FILLED` | Order filled, this could be partially filled. | | `MODIFIED` | Order successfully modified. | | `CANCELLED` | Order successfully cancelled. | | `CANCELLED_STP` | Order cancelled by self trade prevention. | | `REJECTED` | Order rejected | | `NO_SUCH_ORDER` | Cancel rejected, no such order exists. | | `INVALID_ORDER_TYPE` | Invalid order type. | | `BAD_SYMBOL` | Invalid symbol. | | `PRICE_LESS_THAN_MIN_PRICE` | Price less than minimum price for this symbol. | | `PRICE_GREATER_THAN_MAX_PRICE` | Price greater than maximum price for this symbol. | | `CANNOT_MODIFY_NO_SUCH_ORDER` | Failed to modify this order. Order does not exist. | | `CANNOT_MODIFY_PARTIAL_FILL` | Cannot modify partially filled order. Please cancel your current order and place a new order. | | `CANNOT_MODIFY_ALO_WOULD_CROSS` | Cannot modify an ALO order which would cause it cross the market. | | `FAILED_MARGIN_CHECK` | Failed margin check. Please check your available balance. | | `REJECTED_MUST_CHANGE_VALUE_MODIFY` | Modify request did not change a required value. | | `NO_CHANGE_NO_UPDATE` | No values changed, so the order was not updated. | | `INVALID_TICK_SIZE_PRECISION_PRICE` | Invalid tick size for this symbol. Check the price tick size in the reference data. | | `INVALID_TICK_SIZE_PRECISION_QUANTITY` | Invalid lot size for this symbol. Check the lot size in the reference data. | | `QUANTITY_LESS_THAN_MIN_QUANTITY` | Quantity less than minimum for this symbol. Check the minimum quantity in the reference data. | | `QUANTITY_GREATER_THAN_MAX_QUANTITY` | Quantity greater than maximum for this symbol. Check the maximum quantity in the reference data. | | `REJECTED_GREATER_THAN_MAX_PRICE_BAND` | Price is above the permitted price band. | | `REJECTED_LESS_THAN_MIN_PRICE_BAND` | Price is below the permitted price band. | | `INVALID_TIME_IN_FORCE` | Invalid time in force for this order type. | | `REJECTED_WOULD_BREACH_MAX_POSITION` | Order would breach the maximum position limit. | | `REJECTED_WOULD_BREACH_MAX_NOTIONAL` | Would breach max notional limits. | | `REJECTED_MARKET_CLOSED` | QFEX is currently not accepting orders for this symbol. | | `USER_IN_LIQUIDATION` | User is currently being liquidated. | | `REJECTED_FAILED_TO_PROCESS` | Failed to process order. | | `INVALID_TAKE_PROFIT_PRICE` | Invalid take-profit price. | | `INVALID_STOP_LOSS_PRICE` | Invalid stop-loss price. | | `INVALID_CLIENT_ORDER_ID` | Client order ID is invalid. | | `RATE_LIMITED` | You have sent too many requests to trade.qfex.com. Please contact [support@qfex.com](mailto:support@qfex.com) to raise your limits. | | `REJECTED_TOO_MANY_OPEN_ORDERS` | You have reached the max number of open orders. | | `REJECTED_OPEN_INTEREST_LIMIT` | You have reached the max Open Interest limit for a given symbol. | | `REJECTED_TOTAL_OPEN_INTEREST_LIMIT` | Order would breach the total open-interest limit. | | `REJECTED_LESS_THAN_MIN_NOTIONAL` | Order notional is below the permitted minimum. | ## SymbolStatus | Name | Description | | ---------- | -------------------------------- | | `ACTIVE` | Symbol is active. | | `INACTIVE` | Symbol is temporarily suspended. | | `DELISTED` | Symbol is permanently suspended. | ## CandlesInterval Use the wire value when subscribing to the WebSocket candle channel. The symbolic name is the corresponding internal enum name. | Wire value | Symbolic name | Description | | ---------- | ----------------- | ----------------- | | `1MIN` | `ONE_MINUTE` | 1 minute candle. | | `5MINS` | `FIVE_MINUTES` | 5 minute candle. | | `15MINS` | `FIFTEEN_MINUTES` | 15 minute candle. | | `30MINS` | `THIRTY_MINUTES` | 30 minute candle. | | `1HOUR` | `ONE_HOUR` | 1 hour candle. | | `4HOURS` | `FOUR_HOURS` | 4 hour candle. | | `1DAY` | `ONE_DAY` | 1 day candle. | ## ExecutionType | Name | Description | | ------------- | --------------------------- | | `NEW` | User placed order. | | `LIQUIDATION` | Forced liquidation by QFEX. | # Introduction Source: https://docs.qfex.com/api-reference/introduction QFEX provides a unified interface for trading and market data via: * **CLI**: JSON-only command-line access for human operators and AI agents. * **WebSocket**: Low latency, real-time market data and order entry. If you want to integrate QFEX into an agentic trading workflow without managing WebSocket connections directly, use the [QFEX CLI](/api-reference/cli). ## Authentication & API Keys All API calls must be authenticated with an **API Key**. You can create and manage your keys from your QFEX dashboard: 1. Sign in at [qfex.com](https://qfex.com) and select your profile in the bottom right corner. 2. Navigate to **Developer Settings** via the carousel. 3. Click **Generate public and secret API Keys**. 4. Ensure you have 2FA Enabled. 5. Provide a descriptive name, and confirm. 6. **Copy** the generated key and store it securely — it will only be shown once. # Candles Source: https://docs.qfex.com/api-reference/rest/market-data/candles /api-reference/openapi.yaml get /candles/{symbol} Return OHLCV candles for a symbol over a time range. # Contracts Source: https://docs.qfex.com/api-reference/rest/market-data/contracts /api-reference/openapi.yaml get /md/contracts Return mandatory contract metadata and current market data for all symbols. # DefiLlama Metrics Source: https://docs.qfex.com/api-reference/rest/market-data/defillama-metrics /api-reference/openapi.yaml get /defillama/metrics Return QFEX aggregate volume and USD open interest metrics for DefiLlama. # Funding Historic Source: https://docs.qfex.com/api-reference/rest/market-data/funding-historic /api-reference/openapi.yaml get /funding/{symbol} Return historic funding rates for a symbol over a time range with forward filling. # Open Interest Historic Source: https://docs.qfex.com/api-reference/rest/market-data/open-interest-historic /api-reference/openapi.yaml get /open-interest/{symbol} Return historic open interest for a symbol over a time range with forward filling. # Order Book Source: https://docs.qfex.com/api-reference/rest/market-data/order-book /api-reference/openapi.yaml get /md/orderbook/{ticker_id} Return current order book depth for a ticker. # Refdata Source: https://docs.qfex.com/api-reference/rest/market-data/refdata /api-reference/openapi.yaml get /refdata Return symbol reference data. # Settlement Calendar Source: https://docs.qfex.com/api-reference/rest/market-data/settlement-calendar /api-reference/openapi.yaml get /settlement-calendar Return the settlement calendar entry for a symbol at a given time, based on active_until. # Settlement Prices Source: https://docs.qfex.com/api-reference/rest/market-data/settlement-prices /api-reference/openapi.yaml get /settlement-prices Return current and historic settlement prices and ratios. # Symbol Long Short Historic Source: https://docs.qfex.com/api-reference/rest/market-data/symbol-long-short-historic /api-reference/openapi.yaml get /symbol-long-short/{symbol} Return historic long and short user counts for a symbol over a time range. # Taker Volume Historic Source: https://docs.qfex.com/api-reference/rest/market-data/taker-volume-historic /api-reference/openapi.yaml get /taker-volume/{symbol} Return historic taker volume metrics for a symbol over a time range. # Underlier Historic Source: https://docs.qfex.com/api-reference/rest/market-data/underlier-historic /api-reference/openapi.yaml get /underlier/{symbol} Return historic underlier OHLC data for a symbol over a time range. # Hourly PnL (approx. first position per hour) Source: https://docs.qfex.com/api-reference/rest/pnl/hourly-pnl-approx-first-position-per-hour /api-reference/openapi.yaml get /pnl Return approximate first position per symbol per hour for the user, including realised/unrealised pnl, net_funding, fees, quantity, and cost. # Public Account Source: https://docs.qfex.com/api-reference/rest/public/public-account /api-reference/openapi.yaml get /public/accounts/{account_id} Return profile metadata for a public account. # Public Account Historic PnL Source: https://docs.qfex.com/api-reference/rest/public/public-account-historic-pnl /api-reference/openapi.yaml get /public/accounts/{account_id}/historic-pnl Return historic PnL for a public account. # Public Account Positions Source: https://docs.qfex.com/api-reference/rest/public/public-account-positions /api-reference/openapi.yaml get /public/accounts/{account_id}/positions Return open positions for a public account without balance details. # Public Account Trades Source: https://docs.qfex.com/api-reference/rest/public/public-account-trades /api-reference/openapi.yaml get /public/accounts/{account_id}/trades Return trades for a public account. # Public Leaderboard Source: https://docs.qfex.com/api-reference/rest/public/public-leaderboard /api-reference/openapi.yaml get /public/leaderboard Return public account leaderboard rankings by absolute PnL or percentage return. # Public Trades Source: https://docs.qfex.com/api-reference/rest/public/public-trades /api-reference/openapi.yaml get /public/trades Return public account trades for a symbol and time range for chart overlays. # Account Equity Source: https://docs.qfex.com/api-reference/rest/user/account-equity /api-reference/openapi.yaml get /user/account-equity Return total account equity over time for preset durations. # Create Invitation Codes Job Source: https://docs.qfex.com/api-reference/rest/user/create-invitation-codes-job /api-reference/openapi.yaml post /user/invitation-codes/job Run invitation-code reconciliation for the authenticated user. # Create Subaccount Source: https://docs.qfex.com/api-reference/rest/user/create-subaccount /api-reference/openapi.yaml post /user/subaccounts Allocates a new subaccount UUID for the authenticated user and returns it in the response body. # Executions Source: https://docs.qfex.com/api-reference/rest/user/executions /api-reference/openapi.yaml get /executions Return executions (funding, deposits, withdrawals, referral rewards) for the authenticated account, globally sorted by created_at. # Historic Orders Source: https://docs.qfex.com/api-reference/rest/user/historic-orders /api-reference/openapi.yaml get /user/historic-orders Return historic orders (filled or terminally closed) for the authenticated user. # Historic TWAPs Source: https://docs.qfex.com/api-reference/rest/user/historic-twaps /api-reference/openapi.yaml get /user/historic-twaps Return historic TWAPs (cancelled or completed) for the authenticated user. # Historic User PnL Source: https://docs.qfex.com/api-reference/rest/user/historic-user-pnl /api-reference/openapi.yaml get /user/historic-pnl Return historic user pnl change over preset durations. Supports number and percent units, and optional comma-separated symbol filters. # List Account Available Balances Source: https://docs.qfex.com/api-reference/rest/user/list-account-available-balances /api-reference/openapi.yaml get /user/subaccounts/balance Returns the authenticated user's primary account and each secondary account together with current available balance from the latest user position balance snapshot. # List Account Equities Source: https://docs.qfex.com/api-reference/rest/user/list-account-equities /api-reference/openapi.yaml get /user/subaccounts/equity Returns the authenticated user's primary account and each secondary account together with current account equity from the latest user position balance snapshot. # List Subaccounts Source: https://docs.qfex.com/api-reference/rest/user/list-subaccounts /api-reference/openapi.yaml get /user/subaccounts Returns secondary account IDs for the authenticated user (accounts except the primary row where account_id equals user_id). # List User Public Accounts Source: https://docs.qfex.com/api-reference/rest/user/list-user-public-accounts /api-reference/openapi.yaml get /user/public-accounts Returns the authenticated user's primary account and subaccounts with their public sharing state. # Redeem Invitation Code Source: https://docs.qfex.com/api-reference/rest/user/redeem-invitation-code /api-reference/openapi.yaml post /redeem-invitation-code Redeem a valid invitation code for the authenticated user, create the referral link, and enable user access. # Set User Leverage Source: https://docs.qfex.com/api-reference/rest/user/set-user-leverage /api-reference/openapi.yaml post /user/leverage Set the leverage for the authenticated user. # Set User Public Account Source: https://docs.qfex.com/api-reference/rest/user/set-user-public-account /api-reference/openapi.yaml put /user/public-accounts/{account_id} Sets whether one of the authenticated user's accounts is visible in public social features. # Stream Historic Orders CSV Source: https://docs.qfex.com/api-reference/rest/user/stream-historic-orders-csv /api-reference/openapi.yaml get /historic-orders-csv Stream a CSV of all historic orders for the authenticated user. # Stream Historic TWAPs CSV Source: https://docs.qfex.com/api-reference/rest/user/stream-historic-twaps-csv /api-reference/openapi.yaml get /historic-twaps-csv Stream a CSV of all historic TWAPs for the authenticated user. # Stream Trades CSV Source: https://docs.qfex.com/api-reference/rest/user/stream-trades-csv /api-reference/openapi.yaml get /trades-csv Stream a CSV of all trades for the authenticated user. # Transfer Balance Source: https://docs.qfex.com/api-reference/rest/user/transfer-balance /api-reference/openapi.yaml post /user/transfer Transfer balance between two of the authenticated user's accounts (parent account or subaccounts). # User Fees Source: https://docs.qfex.com/api-reference/rest/user/user-fees /api-reference/openapi.yaml get /user/fees Return the fee schedule for the authenticated user. Fees are user-level and do not change when a subaccount is selected. # User Flat Funding Source: https://docs.qfex.com/api-reference/rest/user/user-flat-funding /api-reference/openapi.yaml get /user/flat-funding Return per-symbol net funding from the most recent snapshot where the authenticated account's position was flat. # User Positions Source: https://docs.qfex.com/api-reference/rest/user/user-positions /api-reference/openapi.yaml get /user/positions Return current positions for the authenticated user. # User Referral Notional Volume Source: https://docs.qfex.com/api-reference/rest/user/user-referral-notional-volume /api-reference/openapi.yaml get /user/referrals/notional-volume Return 14-day notional volume for the authenticated user and their direct referrals. # User Referral Rewards Source: https://docs.qfex.com/api-reference/rest/user/user-referral-rewards /api-reference/openapi.yaml get /user/referral-rewards Return daily referral rewards for the authenticated user. # User Trades Source: https://docs.qfex.com/api-reference/rest/user/user-trades /api-reference/openapi.yaml get /user/trade Return trades for the authenticated user. # User Volume Source: https://docs.qfex.com/api-reference/rest/user/user-volume /api-reference/openapi.yaml get /user/volume Return daily user notional volume for one of: 1w, 1m, ytd, or all time. Supports optional comma-separated symbol filters. # Bug Bounty Source: https://docs.qfex.com/legal/bug-bounty ## **Bug Bounty Program Overview** * QFEX encourages responsible disclosure of security vulnerabilities through our Bug Bounty program. * Researchers must follow the written policy. This policy is not negotiable. * Key rules: * Act in good faith and avoid policy violations. * Don’t do more than needed to prove a vulnerability. * Don’t make threats or ransom demands. * Report vulnerabilities, including instructions and proof of concept exploit, as soon as discovered and validated. * Researchers are responsible for complying with all applicable laws. * Attempts to subvert or violate our policy will result in immediate ineligibility for this program. Threats or extortion attempts may be referred to law enforcement. * If you’re unsure about something, notify [bugbounty@qfex.com](mailto:bugbounty@qfex.com) for clarification. ## **Policy** QFEX strongly believes in the value of security professionals and developers assisting in keeping our products and users safe. QFEX has established and encourages coordinated vulnerability disclosure (CVD) via our Bug Bounty Program. The Bug Bounty program serves the QFEX mission by helping protect customers in the digital currency market. By looking for bugs in QFEX systems, you agree to keep all data, information about vulnerabilities, your research, and communications with QFEX strictly confidential until QFEX has addressed the issue and granted permission for disclosure. Where the requirements of this Policy are complied with, QFEX agrees not to initiate legal action for security research performed following all posted QFEX Bug Bounty policies, including good faith, accidental violations. Please avoid deliberate privacy violations by creating test accounts whenever possible. Should you encounter personally identifiable information (‘PII’) or other sensitive data for accounts you do not have express written consent of the account owner to use to validate your findings, please stop accessing that data immediately, and report the issue to QFEX with a description of the PII or other sensitive data, not the data itself. In alignment with data protection regulations and our privacy policies, you must: * Not store or transmit other clients’ PII. If you should happen to capture any client PII, report it to QFEX immediately and then destroy all copies of PII that are not yours. * Minimize data collection and access during your research. Only collect and retain information absolutely necessary to demonstrate and report the vulnerability. * Immediately and securely delete all collected data once the report is submitted and QFEX has confirmed that it has received it. * Not disclose any vulnerabilities or associated information to third parties without QFEX's express written consent. This includes but is not limited to social media, other companies, or the press. * If you are reporting a data breach or the location of a data repository instead of a security vulnerability, please supply the location of the data and do not access it further, nor share the location of the data with others. A bug bounty submission must never contain threats or any attempts at extortion. We are open to paying bounties for legitimate findings, however ransom demands are not eligible for payment. For example, not releasing information about the vulnerability or otherwise hindering the ability to resolve the vulnerability until other demands are met will be deemed a ransom demand. We may be required by law or voluntarily decide to report to authorities any bug bounty submission that contains ransom demands. We believe activities conducted consistent with this policy constitute “authorized” conduct under the Computer Fraud and Abuse Act (CFAA), the Digital Millennium Copyright Act (DMCA), and applicable anti-hacking laws such as Cal. Penal Code 503(c). We will not bring a claim against researchers for circumventing the technological measures we have used to protect the applications in scope of the Bug Bounty Program. However, following this policy does not mean that QFEX nor any other individual organization or government can grant immunity from global laws. It is the responsibility of individual security researchers to understand and comply with all applicable local and international laws regarding anti-hacking, data and privacy, and export controls. If a third party brings legal action against you and you were following the terms in this policy, QFEX will inform the pertinent law enforcement agencies or civil plaintiffs that your research activities were, to the best of our knowledge, conducted pursuant to, and in compliance, with the terms and conditions of this program. It is required that each researcher submit a notification to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. We welcome suggestions for policy clarifications that help researchers conduct their research and reporting with confidence. ## **Rewards** All bounty submissions are rated by QFEX and paid out based on vulnerability rating. All payouts will proceed in BTC to your verified QFEX Account and are defined as a guideline and subject to change. * All bug reports must be submitted to [bugbounty@qfex.com](mailto:bugbounty@qfex.com), the only official contact for this program. Please do not use external sites to submit vulnerability details. Any external sites or portals are unofficial and are not approved by QFEX. * To receive bug bounty payments, you must: * Register at the Intermediate level. See: Create an Account- [https://www.qfex.com/signup](https://www.qfex.com/signup) * Have an ACTIVE account * Provide documentation for verification. * Asking for payment or other acknowledgment in exchange for vulnerability details will result in immediate ineligibility of bounty payments. Not releasing vulnerability details will also result in immediate ineligibility of bounty payments. * Provide detailed instructions to reproduce the vulnerability and a Proof of Concept. * If we cannot reproduce your findings, your report will not be eligible for payout. Exploit only what is needed to prove a security vulnerability and promptly return any assets that have been extracted. * Disclosing vulnerability to other individuals is prohibited. * Any attempt to bypass the procedures outlined in this policy will result in immediate ineligibility of bounty payments. * Include your Bitcoin (BTC) Address for Payment. All rewards will be issued in Bitcoin. * Payment minimums are defined below. All payments may be modified at QFEX's discretion. * The minimum payout is Bitcoin (BTC)  equivalent of \$500 USD. ## **Submission Process** The following steps are taken to process a Bug Bounty submission: 1\. Report is submitted to bug bounty mailbox 2\. QFEX security acknowledges submission (SLA 1 Business Day) 3\. QFEX security triages the submission (SLA 10 Business Days) 4\. QFEX security sends response with determination, if deemed a vulnerability, notification includes severity level and amount of reward (we will ask for a BTC address) 5\. For security vulnerabilities, QFEX will send the reward (SLA 14 Business Days) | Payout Scale | Severity | Range | | ------------ | --------------- | ----------------- | | | Low Severity | \$500-\$1000 | | | Medium Severity | \$2,500-\$5,000 | | | High Severity | \$20,000-\$50,000 | In Scope | URL | Property Name | | ----------------------------------- | -------------- | | [www.qfex.com](http://www.qfex.com) | Main Website | | api.qfex.com | REST API | | http.qfex.com | REST API | | restapi.qfex.com | REST API | | trade.qfex.com | WebSockets API | | mds.qfex.com | WebSockets API | ## **Vulnerability Ratings** **High** High severity issues allow an attacker to read or modify highly sensitive data that they are not authorized to access. They are generally more narrow in scope than critical issues, though they may still grant an attacker extensive access. For example: * arbitrary code/command execution on a server in our production network. * arbitrary queries on a production database. * bypassing our sign-in process, either password or 2FA. * access to sensitive production user data or access to internal production systems. * XSS which bypasses CSP * Discovering sensitive user data in a publicly exposed resource * Gaining access to a non-critical, system to which an end user account should not have access **Medium** Medium severity issues allow an attacker to read or modify limited amounts of data that they are not authorized to access. They generally grant access to less sensitive information than high severity issues. For example: * Disclosing non-sensitive information from a production system to which the user should not have access * XSS that does not bypass CSP or does not execute sensitive actions in another user’s session * CSRF for low risk actions **Low** Low severity issues allow an attacker to access extremely limited amounts of data. They may violate an expectation for how something is intended to work, but it allows nearly no escalation of privilege or ability to trigger unintended behavior by an attacker. For example: * Triggering verbose or debug error pages without proof of exploitability or obtaining sensitive information. ### Ineligibility Reports in which we are not interested and are not eligible for reward include: * Vulnerabilities on sites hosted by third parties (status.qfex.com, etc) unless they lead to a vulnerability on the main website. Vulnerabilities and bugs on the QFEX blog (blog.qfex.com). * Vulnerabilities contingent on physical attack, social engineering, spamming, DDOS attack, etc. * Vulnerabilities affecting outdated or unpatched browsers. * Vulnerabilities in third party applications that make use of QFEX's API. * Vulnerabilities publicly disclosed in third party libraries or technology used in QFEX products, services, or infrastructure earlier than 30 days after the public disclosure of the issue. * Vulnerabilities that have been released publicly prior to QFEX issuing a comprehensive fix. * Vulnerabilities already known to us, or already reported by someone else (reward goes to first reporter). * Issues that aren't reproducible. * Vulnerabilities that require an improbable level of user interaction. * Vulnerabilities that require root/jailbreak on mobile. * Missing security headers without proof of exploitability. * TLS Cipher Suites offered. * Suggestions on best practices. * Software version disclosure. * Any report without detailed step-by-step instructions and an accompanying proof of concept exploit. * Issues that we can't reasonably be expected to do anything about, such as issues in technical specifications that QFEX must implement to conform to those standards. * The output from automated tools/scanners or AI-generated reports. * Issues without any security impact. ### Non-security Issues You can let us know about non-security issues at [support@qfex.com](mailto:support@qfex.com). # Client Agreement Source: https://docs.qfex.com/legal/client-agreement Last Updated: 28 November 2025 This Client Agreement (“Agreement”) is entered into by and between: **QFEX Inc.** (“QFEX,” “we,” “us,” or “our”) AND The **Client**, whose details are set out in the Account Application Form (“you,” “your,” or “the Client”). By opening an account with QFEX or using any of our websites, application programming interfaces, or mobile applications (collectively, the “Site”), you acknowledge that you have read, understood, and agree to be bound by the terms and conditions set forth in this Agreement, together with the [Privacy Policy](https://docs.qfex.com/legal/privacy-policy) and **Trading Rulebook**, which are incorporated herein by reference. *** ### 1. Introduction and Scope of Services #### 1.1 Nature of Services QFEX operates a **Multilateral Trading Facility (MTF)** that enables electronic trading in cash-settled perpetual futures contracts across multiple asset classes, including but not limited to equity indices, single-name equities, foreign exchange pairs, and commodities (collectively, the “Services”). QFEX acts as the operator and facilitator of the MTF but does not act as a counterparty or principal in any trade executed on the platform. Access to the MTF is provided via the Site. #### 1.2 No Advisory Relationship QFEX does not provide investment, financial, legal, accounting, tax, or regulatory advice. All trading or investment decisions undertaken by you are made at your sole discretion and risk. You acknowledge that no communication from QFEX should be construed as advice or a recommendation to engage in any particular transaction. #### 1.3 Supplemental Terms Certain products or services offered by QFEX may be subject to additional terms, conditions, or disclosures, which form part of this Agreement once you begin using such products or services. *** ### 2. Eligibility #### 2.1 Eligible Clients To be eligible to use QFEX Services, you must: * (a) be at least eighteen (18) years of age; * (b) have the legal capacity to enter into binding contracts; * (c) reside in a jurisdiction where use of the QFEX Services is lawful and not restricted by local regulation; * (d) not be on any of the following lists: * the Specially Designated Nationals and Blocked Persons List and the Sectoral Sanctions Identification List maintained by the U.S. Treasury Department's Office of Foreign Assets Control; * the Denied Persons List, Entity List, and Unverified List maintained by the U.S. Commerce Department's Bureau of Industry and Security; * the non-proliferation sanctions lists maintained by the U.S. State Department; * the United Nations Security Council Consolidated List; * the Consolidated List of Financial Sanctions Targets maintained by the UK Treasury; * similar lists maintained by the European Union. #### 2.2 Prohibited Jurisdictions You represent and warrant that you are **not** a resident of any jurisdiction in which the use of similar services would violate applicable law or regulation, including, without limitation, the United States, France, Cuba, Iran, Russia, North Korea, Sudan, Spain, the United Kingdom, Myanmar, Venezuela, Belarus, or the territories of Luhansk and Donetsk. QFEX reserves the right, at its sole discretion and without prior notice, to update or expand the list of prohibited jurisdictions. #### 2.3 Client Representations By submitting an account application, you represent and warrant that: * (a) all information provided is true, complete, and accurate; * (b) you will immediately notify QFEX of any material changes to your information; * (c) your participation in QFEX Services does not violate any law, regulation, or order applicable to you. #### 2.4 Approval and Discretion All account applications are subject to review and approval at QFEX’s absolute discretion. QFEX may approve, reject, or impose restrictions on any account without providing a reason. *** ### 3. Account Opening, Data, and AML #### 3.1 Application Requirements QFEX reserves the right to request documentation, including submission of an **Account Application Form** and required **Know Your Customer (KYC)** and **Anti-Money Laundering / Counter-Terrorist Financing (AML/CTF)** documentation, as well as other proofs of identity, address, and source of funds. #### 3.2 Account Responsibility You may only hold one active QFEX account unless expressly authorized by QFEX. You are solely responsible for maintaining the security and confidentiality of your account credentials and for all activity conducted under your account. #### 3.3 AML and Compliance Obligations You agree to comply with all applicable AML/CTF requirements. QFEX may, in its sole discretion, freeze, restrict, or terminate your account if suspicious activity is detected or if you fail to provide requested information. QFEX reserves the right to disclose information to relevant authorities when legally required. #### 3.4 Data Protection QFEX processes personal data in accordance with its [Privacy Policy](https://docs.qfex.com/legal/privacy-policy), available on the Site. By entering into this Agreement, you consent to such data processing and represent that any personal data you provide relating to third parties has been lawfully obtained. #### 3.5 Information Accuracy You must ensure that all information and documentation you provide is accurate and up to date. QFEX may suspend or close accounts containing false, misleading, or incomplete information. *** ### 4. Trading and Execution #### 4.1 Access and Use Upon approval, you are granted a non-exclusive, limited, and revocable right to access the QFEX platform for lawful trading purposes. All rights not expressly granted herein are reserved by QFEX. You may not sublicense, transfer, or permit third-party access to your account. #### 4.2 Orders and Margin Maintenance You are responsible for all orders placed using your credentials, whether authorized by you or not. You must maintain sufficient margin in accordance with QFEX’s **Trading Rulebook**. QFEX may reject or cancel any order that breaches margin or risk parameters. #### 4.3 Leverage and Risk Controls Leverage limits and margin requirements may vary based on your classification and the product traded. QFEX may adjust leverage parameters at its sole discretion to reflect market conditions or regulatory obligations. #### 4.4 Market Protections QFEX may implement trading controls, including price bands, circuit breakers, and position limits, to ensure orderly markets and mitigate volatility. Such measures may be applied without prior notice. #### 4.5 Suspension, Termination, and Cancellation of Access QFEX may refuse to process, cancel, reverse, or block any transaction or temporarily suspend or permanently terminate your access to its Services under any of the following circumstances: * if required by a court order or governmental authority; * if you fail to settle outstanding fees or margin obligations within the prescribed time; * if your account shows indications of insolvency, manipulation, fraud, or other prohibited conduct; * if you breach any provision of this Agreement or other QFEX policies; or * if QFEX determines, in its sole discretion, that suspension is necessary to protect the integrity or security of the platform. If suspension or termination occurs, QFEX will provide notice where legally permissible and will restore access once the reason for suspension no longer exists. QFEX shall not be liable for losses resulting from inability to trade during such periods. #### 4.6 Service Interruptions QFEX may temporarily suspend Services for maintenance, upgrades, or other operational reasons. While QFEX will endeavor to provide prior notice where feasible, interruptions may occur without warning. QFEX is not liable for losses resulting from downtime or system unavailability. *** ### 5. Client Money #### 5.1 Segregation of Funds All fiat currency and digital assets (“Client Money”) belonging to clients shall be held in **segregated accounts** maintained with appropriately licensed custodians. These accounts will be maintained separately from QFEX’s own operational funds. #### 5.2 Interest and Beneficial Ownership Unless otherwise stated, Client Money held by QFEX will not accrue interest. Where interest is generated, QFEX reserves the right to retain such interest as beneficial owner. Any change in this policy will be communicated to clients in writing. #### 5.3 Deposits and Withdrawals Deposits and withdrawals must originate from or be directed to a bank account held in your name. Only one nominated account may be linked at any given time. QFEX reserves the right to request proof of ownership or source of funds for any transaction. Requests may be denied or delayed where compliance verification is pending. #### 5.4 Transaction Monitoring All deposits and withdrawals are subject to transaction monitoring in line with QFEX’s AML/CTF framework. QFEX may block, reverse, or withhold transactions deemed suspicious and may request additional supporting documentation. #### 5.5 Fiat Currency Transactions QFEX may facilitate conversions between fiat currency and digital assets as listed on the Site. The availability of fiat pairs depends on jurisdictional factors, user verification status, and the capabilities of third-party payment processors. Pricing, fees, and applicable charges will be displayed before execution. #### 5.6 Third-Party Transfers QFEX bears no responsibility for the performance, quality, legality, or delivery of goods or services obtained from or provided to third parties using digital assets. Any disputes arising from third-party transactions must be resolved directly between you and such third party. #### 5.7 Reconciliation and Recordkeeping QFEX performs regular reconciliations of Client Money accounts and maintains accurate records in compliance with applicable regulations. *** ### 6. Reserve Fund #### 6.1 Purpose and Structure QFEX maintains an insurance reserve (the “Reserve Fund”) on behalf of its clients who participate in derivatives trading on the QFEX platform. The Reserve Fund is designed to absorb potential shortfalls arising from negative equity balances that occur during periods of market volatility or liquidation. #### 6.2 Funding of the Reserve Fund The Reserve Fund is primarily funded through excess collateral and residual margin obtained from liquidations executed via QFEX’s **Designated Liquidation Program (DLP)** or similar mechanisms. The fund may be supplemented from other sources at QFEX’s discretion to maintain adequate coverage levels. #### 6.3 Operation of the Reserve Fund The objective of the Reserve Fund is to ensure that client account balances cannot become negative such that a client owes funds to QFEX. However, QFEX does not warrant or represent that the Reserve Fund will always be sufficient to cover all losses, especially under conditions of extreme market stress. #### 6.4 Limitation of Liability In circumstances where the Reserve Fund is depleted or insufficient, QFEX may, as a protective measure, **liquidate profitable open positions of other clients** solely to the extent necessary to offset collective deficits. You acknowledge and accept that participation in the QFEX trading system implies consent to this risk allocation structure. *** ### 7. Risk Disclosure #### 7.1 High-Risk Nature of Trading Trading in perpetual futures and other derivative products offered on QFEX involves **substantial risk** and may not be suitable for all investors. Prices may fluctuate rapidly, and losses may exceed the amount initially invested. You should not trade unless you can afford to lose the entirety of your investment. #### 7.2 Acknowledgment of Risk By using QFEX Services, you represent that you understand and are willing to assume the economic, legal, and other risks involved in such trading. You further confirm that you have the necessary experience, knowledge, and resources to assess these risks. #### 7.3 No Assurance of Profit QFEX does not guarantee that trading on the platform will be profitable or loss-free. Past performance does not indicate future results. #### 7.4 Independent Judgment All decisions to open or close positions are made at your sole discretion. You acknowledge that no communication from QFEX should be construed as investment advice or a recommendation. *** ### 8. Fees and Charges #### 8.1 Applicable Fees All applicable trading fees, commissions, and charges are published in the **Trading Rulebook** section available on the QFEX Site. You agree to review and comply with the fee schedule in effect at the time of each transaction. #### 8.2 Changes to Fees QFEX reserves the right to modify, introduce, or remove any fees or charges by providing prior notice via the Site or other communication channels. Any fee change shall become effective upon posting unless otherwise specified. #### 8.3 Payment of Fees You are responsible for ensuring sufficient funds are available in your account to cover all applicable fees. QFEX may deduct such fees automatically from your account balance without further notice. #### 8.4 Third-Party Fees You acknowledge that additional charges, such as network fees, bank transfer costs, or fees levied by payment processors, may apply and are not controlled by QFEX. These costs shall be borne solely by you. *** ### 9. Data Protection and Security #### 9.1 Data Processing and Compliance QFEX processes personal and transactional data in accordance with its [Privacy Policy](https://docs.qfex.com/legal/privacy-policy) and applicable data protection laws. By entering into this Agreement, you consent to such processing and warrant that all data provided to QFEX is accurate, current, and complete. #### 9.2 Client Responsibilities If you provide personal data concerning other individuals (such as employees, directors, or beneficial owners), you must ensure that: * such disclosure is lawful under applicable data protection legislation; and * those individuals have been informed of QFEX’s [Privacy Policy](https://docs.qfex.com/legal/privacy-policy) and their data rights. #### 9.3 Security Credentials You are responsible for maintaining **strict confidentiality** over your login credentials, passwords, and two-factor authentication (2FA) tokens. QFEX will never request your password, 2FA codes, or remote access to your device. You must not share your login details with third parties under any circumstance. #### 9.4 Device Security You must take all reasonable precautions to secure the devices used to access your account. This includes using strong passwords, enabling encryption, installing reputable antivirus software, and ensuring that your device is free from malware. #### 9.5 Unauthorized Access Any compromise of your login credentials or electronic devices may result in unauthorized access to your account, including theft of assets. QFEX is not responsible for losses arising from such unauthorized activity if due to your negligence or failure to maintain security. #### 9.6 Security Breach Notification If you become aware of, or suspect, any unauthorized access, fraud, or cyber incident involving your account or QFEX systems (“Security Breach”), you must immediately: * (a) notify QFEX Support at [support@qfex.com](mailto:support@qfex.com); * (b) provide accurate and timely information during QFEX’s investigation; and * (c) follow any reasonable instructions issued by QFEX to mitigate risk. Notification of a Security Breach does not guarantee reimbursement for any losses incurred. #### 9.7 Cybersecurity and Phishing Risks QFEX is not liable for damage or interruption caused by viruses, phishing, spoofing, or other cyber threats. Clients are encouraged to exercise vigilance when interacting with emails or messages purporting to originate from QFEX. Official communications will only be sent from verified QFEX domains. *** ### 10. Liability #### 10.1 General Release In the event of any dispute between you and another user of QFEX Services, you agree to release QFEX, its affiliates, officers, directors, employees, and service providers from any claims, liabilities, damages, or demands arising out of such dispute. #### 10.2 Indemnification You agree to indemnify, defend, and hold harmless QFEX, its affiliates, and each of their respective officers, directors, agents, and employees from any loss, damage, liability, or expense (including reasonable attorneys’ fees) incurred as a result of: * your breach of this Agreement or any other QFEX policy; * your violation of any law or regulation; or * QFEX’s enforcement of this Agreement against you. #### 10.3 Limitation of Liability QFEX’s aggregate liability to you for any loss, damage, or claim arising under or in connection with this Agreement, whether in contract, tort, or otherwise, shall not exceed the total value of Client Money held in your name at the time of the event giving rise to the claim. Where a claim relates to a specific transaction, QFEX’s liability shall be capped at the notional value of that transaction. #### 10.4 Excluded Losses QFEX, its affiliates, and their respective officers, directors, agents, or employees shall not be liable for any: * (a) indirect, consequential, or special loss; * (b) loss of profits, revenue, data, goodwill, or anticipated savings; * (c) loss of opportunity, business, or reputation; * (d) delays, errors, or inaccuracies in data transmission; * (e) interruptions or suspensions of trading due to market conditions, technical issues, or maintenance; or * (f) events of force majeure beyond QFEX’s reasonable control. #### 10.5 Legal Compliance and Exceptions Nothing in this Agreement shall limit QFEX’s liability in cases of fraud, gross negligence, or willful misconduct, or for death or personal injury caused by QFEX’s negligence where such limitation is prohibited by law. #### 10.6 No Warranties All QFEX Services and the Site are provided on an **“as is” and “as available” basis**. QFEX disclaims all implied warranties, including merchantability, fitness for a particular purpose, and non-infringement. QFEX does not guarantee uninterrupted, timely, or error-free operation of its systems. #### 10.7 Force Majeure QFEX shall not be responsible for any delay, failure, or interruption in performance caused by events beyond its control, including but not limited to natural disasters, war, labor disputes, acts of government, telecommunications failures, or market disruptions. *** ### 11. Termination #### 11.1 Right to Terminate Either party may terminate this Agreement at any time by providing written notice, subject to the settlement of all open positions, fees, and obligations. #### 11.2 Termination by QFEX QFEX may immediately suspend or terminate your account without prior notice if: * (a) your account fails to meet minimum margin requirements as set out in the **Trading Rulebook**; * (b) you breach any obligation under this Agreement or other QFEX policies; * (c) any representation or warranty made by you is or becomes false, misleading, or incomplete; * (d) you become bankrupt, insolvent, or subject to liquidation or receivership; * (e) QFEX suspects fraud, market manipulation, money laundering, or other criminal conduct; or * (f) QFEX, acting reasonably, determines that maintaining your account could pose reputational or operational risk. #### 11.3 Consequences of Termination Upon termination, QFEX may: * close out or liquidate open positions at prevailing market prices; * apply any balance or credit to outstanding debts owed by you; * restrict or delay withdrawals to ensure compliance with applicable laws; * sell any digital assets held on your behalf to discharge obligations; and * accelerate all outstanding liabilities owed to QFEX so that they become immediately due. #### 11.4 Recovery of Costs You shall be liable for reasonable costs, including legal fees, incurred by QFEX in enforcing its rights under this section or recovering amounts due. #### 11.5 Effect of Termination Termination does not affect any rights or obligations that have accrued prior to the effective date of termination. Provisions intended to survive termination (including indemnity, limitation of liability, and governing law) shall remain in force. *** ### 12. Complaints and Dispute Resolution #### 12.1 Contacting QFEX If you have questions, feedback, or concerns regarding QFEX Services, please contact our customer support team via email at [support@qfex.com](mailto:support@qfex.com). We aim to respond promptly and resolve inquiries efficiently. #### 12.2 Filing a Complaint If you wish to file a formal complaint, you must first contact QFEX’s customer support team to attempt resolution. If the issue remains unresolved, you may escalate the complaint by emailing [complaints@qfex.com](mailto:complaints@qfex.com) and providing the following information: * (a) Your full name, registered email address, and account ID; * (b) A clear description of the complaint, including relevant dates, times, and events; * (c) Copies of all supporting documentation, such as screenshots, trade confirmations, or correspondence; * (d) The outcome or resolution you are seeking; * (e) Details of any prior communication with QFEX on the same matter; and * (f) Your preferred method of contact. QFEX will acknowledge receipt of your complaint and conduct an internal review. Unless otherwise required by law, QFEX will aim to respond to complaints within **forty-five (45) business days** from receipt. #### 12.3 Resolution and Final Response Following investigation, QFEX will issue a written response outlining its findings and proposed resolution. Any settlement offer made by QFEX shall not constitute an admission of liability unless explicitly stated. #### 12.4 Arbitration Agreement If a complaint cannot be resolved through QFEX’s internal process, the matter (“Dispute”) shall be referred to **binding arbitration** under the Rules of Arbitration of the International Chamber of Commerce (ICC) then in effect. * (a) The seat of arbitration shall be **Panama City, Republic of Panama**. * (b) The arbitration shall be conducted in English. * (c) The tribunal shall consist of one (1) arbitrator appointed in accordance with ICC rules. * (d) The decision of the arbitrator shall be final and binding upon both parties. #### 12.5 Confidentiality of Proceedings Unless required by law or necessary for enforcement of an award, both parties agree to maintain the confidentiality of all arbitration proceedings, materials, and awards. Disclosure may only occur to the extent required by a legal duty or to pursue a legitimate right in court. #### 12.6 Class Action Waiver You agree that any arbitration or proceeding shall be limited to the dispute between us and you individually. To the fullest extent permitted by law, you agree that: * (a) no arbitration or proceeding shall be joined with any other; * (b) there is no right or authority for any dispute to be arbitrated or resolved on a class-action basis or to utilize class action procedures; and * (c) there is no right or authority for any dispute to be brought in a purported representative capacity on behalf of the general public or any other persons. #### 12.7 Interim Relief Nothing in this section prevents either party from seeking provisional or conservatory measures from a court of competent jurisdiction to protect its rights pending arbitration. *** ### 13. General Provisions #### 13.1 Unclaimed Property If QFEX holds funds on your behalf and no account activity or contact has occurred for **five (5) years**, applicable law may require QFEX to treat such funds as unclaimed property. QFEX may remit such funds to the relevant governmental authority after deducting reasonable administrative costs permitted by law. #### 13.2 Death or Incapacity of Account Holder Upon receipt of official documentation confirming your death or legal incapacity, QFEX will **freeze your account** and suspend all transactions until authorized instructions are received. The appointed executor, administrator, or other legally recognized representative must provide documentation satisfactory to QFEX to facilitate the transfer or closure of the account. QFEX reserves the right to request probate orders or court directives before acting on such instructions. #### 13.3 Entire Agreement This Agreement, including all policies and documents incorporated by reference (such as the [Privacy Policy](https://docs.qfex.com/legal/privacy-policy) and **Trading Rulebook**), constitutes the **entire understanding** between you and QFEX regarding the subject matter hereof and supersedes all prior discussions, representations, or agreements, whether oral or written. #### 13.4 Amendments QFEX may amend this Agreement at any time by posting an updated version on its Site. Amendments will take effect upon posting unless otherwise stated. Continued use of QFEX Services after an update constitutes your acceptance of the revised Agreement. #### 13.5 Assignment and Transfer This Agreement is personal to you and may not be assigned, delegated, or transferred without QFEX’s prior written consent. QFEX may assign or transfer its rights and obligations hereunder to any affiliate or successor entity without prior notice, including in connection with a merger, acquisition, or corporate reorganization. You may terminate the Agreement immediately if you do not agree to such transfer. #### 13.6 Invalidity and Severability If any provision of this Agreement is found invalid, unlawful, or unenforceable by a court of competent jurisdiction, the remaining provisions shall remain in full force and effect. The invalid or unenforceable provision shall be modified to the minimum extent necessary to make it valid and enforceable while preserving its intent. #### 13.7 Waiver No failure or delay by QFEX in exercising any right or remedy under this Agreement shall constitute a waiver of that or any other right or remedy. Any waiver must be in writing and signed by an authorized representative of QFEX. #### 13.8 Notices and Communication * (a) QFEX may provide notices to you electronically via email, your account dashboard, or postings on the Site. * (b) All communications will be deemed received upon transmission unless returned as undeliverable. * (c) You must ensure that your registered email address remains valid and monitored. QFEX is not responsible for any loss arising from your failure to receive notices due to incorrect or inactive contact information. #### 13.9 Recordkeeping QFEX may record communications (including electronic messages and calls) for compliance, audit, and quality assurance purposes. Such records shall remain the property of QFEX and may be used as evidence in any dispute. #### 13.10 Language This Agreement and all related documents shall be drafted and interpreted in **English**. Any translation is provided for convenience only; the English version shall prevail in the event of inconsistency. *** ### 14. Governing Law and Jurisdiction #### 14.1 Governing Law This Agreement, and any claim or dispute arising out of or relating to it or the QFEX Services, shall be governed by and construed in accordance with the laws of the **Republic of Panama**, without regard to conflict of law principles. #### 14.2 Jurisdiction Except where arbitration is required under Section 12, the courts of the **Republic of Panama** shall have exclusive jurisdiction over all disputes arising in connection with this Agreement. #### 14.3 Enforcement of Arbitration Awards Any arbitration award rendered pursuant to Section 12 may be enforced in any court of competent jurisdiction, and both parties irrevocably submit to such jurisdiction for enforcement purposes. *** ### 15. Referral Program #### 15.1 Participation You may participate in our referral program by: * (a) Sharing Referral Links: Using your unique referral link to invite others to join the Waitlist; * (b) Profile Enhancement: Uploading a profile picture to your Account; * (c) Security Setup: Enabling two-factor authentication (2FA) on your Account. #### 15.2 Referral Program Rules * (a) Legitimate Referrals: All referrals must be legitimate and made to real persons who are eligible to participate in the Program. * (b) No Self-Referrals: You may not refer yourself or create multiple Accounts to generate referrals. * (c) No Spam: You may not send unsolicited communications or engage in spamming activities. * (d) Compliance: All referral activities must comply with Applicable Law, including anti-spam and privacy laws. * (e) Modification: We reserve the right to modify, suspend, or terminate the referral program at any time without notice. * (f) Rewards: Rules for the calculation of referral rewards can be found in the [documents](https://docs.qfex.com/qfex/referral). *** ### 16. Miscellaneous #### 16.1 Relationship of the Parties Nothing in this Agreement creates any partnership, joint venture, agency, or fiduciary relationship between you and QFEX. You act solely as a principal when trading, and QFEX acts only as the operator of the trading facility. #### 16.2 Third-Party Rights This Agreement is intended solely for the benefit of the parties hereto. No person or entity other than QFEX and the Client shall have any rights or remedies under this Agreement. #### 16.3 Survival of Terms Provisions relating to indemnity, limitation of liability, confidentiality, governing law, dispute resolution, and any other clauses intended to survive termination shall remain effective after the Agreement terminates. #### 16.4 Headings and Interpretation Section headings are for convenience only and shall not affect interpretation. References to singular terms include the plural and vice versa, and references to “including” shall be deemed to mean “including without limitation”. #### 16.5 The Company QFEX Inc. is a company incorporated under the laws of the **Republic of Panama** with its registered office located at Office 317, Vía Ricardo J. Alfaro, PH The Century Tower, Betania, Panama, Panamá, Panama, 07095. #### 16.6 Execution and Acceptance Your electronic acceptance of this Agreement or continued use of QFEX Services constitutes a legally binding agreement between you and QFEX. #### 16.7 Contact If you have any questions about these Terms, please contact us at: * Email: [legal@qfex.com](mailto:legal@qfex.com) # Cookie Policy Source: https://docs.qfex.com/legal/cookie-policy Last Updated: 28 November 2025 # Cookie Policy This Cookie Policy explains how QFEX Inc. ("QFEX," "we," "us," or "our") uses cookies and similar technologies when you visit our website [qfex.com](https://qfex.com) and its subdomains. This policy explains what these technologies are, why we use them, and your rights to control our use of them. ## What are Cookies? Cookies are small data files that are placed on your computer or mobile device when you visit a website. Cookies are widely used by website owners to make their websites work more efficiently and to provide reporting information. Cookies set by the website owner (in this case, QFEX) are called **first-party cookies**. Cookies set by parties other than the website owner are called **third-party cookies**. Third-party cookies enable third-party features or functionality to be provided on or through the website (e.g., analytics, interactive content, and informational services). ## Why Do We Use Cookies? We use first-party and third-party cookies for several reasons: * **Essential Cookies:** Some cookies are required for technical reasons for our website to operate. * **Performance and Analytics:** We use cookies to analyze how our website is used. * **Functionality:** We use cookies to provide enhanced functionality and personalization. * **Informational Services:** We use cookies to provide relevant informational content and services. ## Types of Cookies We Use ### Essential Cookies | Cookie Name | Purpose | Duration | Type | | -------------- | ---------------------------------------------- | -------- | ----------- | | Session ID | Maintains your session while using the website | Session | First-party | | Authentication | Keeps you logged in to your account | 30 days | First-party | | Security | Protects against cross-site request forgery | Session | First-party | | Load Balancing | Ensures optimal website performance | Session | First-party | **Legal Basis:** These cookies are necessary for the performance of our contract with you and to comply with legal obligations. ### Performance and Analytics Cookies | Cookie Name | Purpose | Duration | Type | | ------------------ | -------------------------------------- | -------- | ----------- | | Google Analytics | Analyzes website usage and performance | 2 years | Third-party | | Internal Analytics | Tracks page views and user journeys | 1 year | First-party | **Legal Basis:** We use these cookies based on our legitimate interest in improving our website and services. ### Functionality Cookies | Cookie Name | Purpose | Duration | Type | | ------------------- | ------------------------------------- | -------- | ----------- | | Language Preference | Remembers your language selection | 1 year | First-party | | Theme Preference | Remembers your display preferences | 1 year | First-party | | Form Data | Temporarily stores form information | Session | First-party | | Referral Tracking | Tracks referral program participation | 90 days | First-party | **Legal Basis:** We use these cookies based on our legitimate interest in providing you with a personalized experience. ### Informational and Educational Cookies | Cookie Name | Purpose | Duration | Type | | -------------------- | ------------------------------------------------ | -------- | ----------- | | Content Preferences | Remembers your informational content preferences | 90 days | First-party | | Educational Progress | Tracks progress through educational materials | 1 year | First-party | | Information Delivery | Enables delivery of relevant information | 90 days | Third-party | | Content Analytics | Measures engagement with informational content | 90 days | First-party | **Legal Basis:** We use these cookies based on your consent, which you can withdraw at any time. ## How to Control Cookies You have several options for managing cookies: ### Browser Settings Most web browsers allow you to control cookies through their settings preferences. You can set your browser to: * Block all cookies * Block third-party cookies only * Delete cookies when you close your browser * Notify you when a cookie is set > **Note:** If you choose to block or delete cookies, some features of our website may not work properly. ### Cookie Consent Manager We provide a cookie consent manager that allows you to: * Accept or reject different categories of cookies * Change your preferences at any time * View detailed information about each cookie You can access the cookie consent manager by clicking the **“Cookie Settings”** link in our website footer. ### Opt-Out Links You can opt out of certain third-party cookies by visiting: * [Google Analytics Opt-out](https://tools.google.com/dlpage/gaoptout) * Other Analytics: Contact us for information about opting out of other analytics services ### Do Not Track Some browsers include a “Do Not Track” feature. Currently, there is no industry standard for how to respond to Do Not Track signals, so we do not currently respond to these signals. ## Other Tracking Technologies In addition to cookies, we may use other tracking technologies: * **Web Beacons:** Small graphics with unique identifiers that track user behavior and email interactions. * **Local Storage:** Used to store information locally on your device for enhanced functionality and performance. * **Fingerprinting:** Collects information about your device and browser configuration to help identify and prevent fraud. ## Third-Party Services We work with third-party service providers who may set cookies on our website: ### Analytics Providers * **Google Analytics:** Provides website analytics and user behavior insights. ### Informational Service Providers * **Content Delivery Networks:** Provides efficient delivery of informational content. * **Educational Platforms:** Provides educational content and progress tracking. ### Customer Support * **Intercom:** Provides customer support chat functionality. * **Zendesk:** Provides customer support ticketing. ### Security Providers * **Cloudflare:** Provides security and performance optimization. * **reCAPTCHA:** Provides bot protection and security. ## International Transfers Some of our third-party service providers may transfer your data internationally. We ensure appropriate safeguards are in place for such transfers, including: * Standard Contractual Clauses * Adequacy decisions * Other appropriate safeguards as required by law ## Data Retention We retain cookie data for different periods depending on the type of cookie: * **Session cookies:** Deleted when you close your browser * **Persistent cookies:** Retained for the period specified in the cookie table above * **Analytics data:** Typically retained for 26 months * **Informational data:** Typically retained for 90 days to 2 years ## Your Rights Depending on your location, you may have certain rights regarding cookies and personal data: * **Right to withdraw consent:** You can withdraw consent for non-essential cookies at any time. * **Right to object:** You can object to processing based on legitimate interests. * **Right to access:** You can request information about cookies and data processing. * **Right to deletion:** You can request deletion of your data in certain circumstances. ## Children's Privacy Our website is not directed to children under 18, and we do not knowingly collect personal information from children under 18 through cookies. ## Updates to This Policy We may update this Cookie Policy from time to time to reflect changes in our practices or applicable law. We will notify you of material changes by: * Posting the updated policy on our website * Sending you an email notification * Displaying a notice on our website ## Contact Us If you have questions about this Cookie Policy or our use of cookies, please contact us: **Email:** [privacy@qfex.com](mailto:privacy@qfex.com) This Cookie Policy should be read in conjunction with our [Privacy Policy](https://qfex.com/privacy). # Privacy Policy Source: https://docs.qfex.com/legal/privacy-policy Last Updated: 28 November 2025 ## Introduction **QFEX Inc.** (“QFEX,” “we,” “us,” or “our”) respects and protects the privacy of those who visit our website (“Users”) and those who sign up for and access our services (“Clients”) — collectively referred to as **“you”** or **“your.”** This Privacy Policy explains how we collect, use, and share personal information when you explore, sign up for, or access our trading platform, including services offered on our website and related trading features. By accessing and using our trading platform, you accept this Privacy Policy and its terms.\ If you do not wish for your personal information to be collected, used, or disclosed as described here — or if you are under 18 years of age — please stop using our platform. ### Key Highlights * We collect and use your information to **provide and improve** our trading platform, ensure **security**, and meet **legal obligations**. * We share your information with **trusted third parties** and service providers to operate the platform and comply with legal requirements. * You have **privacy rights** to request access, correction, or deletion of data we hold about you. * Questions? Contact **[privacy@qfex.com](mailto:privacy@qfex.com)**. ## 1. What Information We Collect We collect information in three main ways: information you provide, information collected automatically, and information obtained from third parties. ### Information You Provide to Us | Information Category | Description | | ----------------------------- | ----------------------------------------------------------------------------------- | | **Basic Information** | Name, email address, phone number, date of birth, country of residence | | **Account Information** | Username, password, profile picture, trading preferences | | **Financial Information** | Bank details, investment experience, income verification, trading history, balances | | **Communication Information** | Survey responses, messages to support, chatbot interactions | | **Trading Information** | Transaction history, orders, positions, risk management preferences | ### Information Collected Automatically | Information Category | Description | | ---------------------------------- | ---------------------------------------------------------------- | | **Device and Browser Information** | Device type, OS, browser, IP address, and network details | | **Usage Information** | Pages visited, time on platform, clicks, and interactions | | **Trading Activity** | Order patterns, trading frequency, and platform usage statistics | ### Information We Obtain from Third Parties | Information Category | Description | | -------------------------------- | ------------------------------------------------------------------ | | **Public Database Information** | Sanctions lists, public records, and regulatory databases | | **Credit and Background Checks** | Data from credit agencies or background check providers | | **Service Partners** | Information from partners about your interactions | | **Analytics Providers** | Website usage and engagement data | | **Market Data Providers** | Information related to trading activities and market participation | ## 2. How We Use Your Information We use personal information to deliver, operate, and improve the QFEX trading platform, ensure security, and comply with regulations. ### A. Data Use Necessary to Perform Our Agreement with You | Purpose | Information Used | | ---------------------------------------- | ------------------------------------------------- | | Create and maintain your account | Basic Information, Account Information | | Provide trading platform services | Basic, Account, Verification, Trading Information | | Process trades and transactions | Basic, Trading, Financial Information | | Provide customer support | Basic, Communication, Usage Information | | Send service communications | Basic, Communication Information | | Calculate and manage margins | Financial, Trading Information | | Execute liquidations and risk management | Trading, Financial Information | ### B. Data Use to Comply with Legal Obligations | Purpose | Information Used | | --------------------------------- | ---------------------------------------------------------- | | Verify your identity | Basic, Verification Information | | Comply with AML/KYC requirements | Basic, Verification, Financial Information | | Respond to legal requests | Any information as required by law | | Regulatory compliance | Basic, Verification, Usage, Financial, Trading Information | | Tax reporting | Basic, Financial, Trading Information | | Market surveillance and reporting | Trading, Usage Information | ### C. Data Use for Our Legitimate Interests | Purpose | Legitimate Interest | Information Used | | ------------------------------------- | ------------------------------------ | ----------------------------------------- | | Improve our trading platform | Enhance user experience and services | Usage, Basic, Trading Information | | Informational communications | Provide relevant educational content | Basic, Usage Information | | Security and fraud prevention | Protect users and platform integrity | All categories as necessary | | Research and analytics | Improve user experience | Usage, Communication, Trading Information | | Risk management | Manage operational risk | All categories as necessary | | Market making and liquidity provision | Maintain orderly markets | Trading, Usage Information | ### D. Data Use Based on Your Consent | Purpose | Information Used | | ------------------------- | ------------------------------ | | Device-based settings | Device and Browser Information | | Optional communications | Basic, Usage Information | | Enhanced trading features | Trading, Usage Information | ## 3. How and Why We Share Your Information We share information with trusted third parties to operate the platform, comply with laws, and provide seamless service. ### Service Providers | Type of Service Provider | Information Shared | | ----------------------------------- | -------------------------------- | | Identity verification services | Basic, Verification Information | | Background check providers | Basic, Verification Information | | Email and communication tools | Basic, Communication Information | | Analytics providers | Usage Information | | Security services | All categories as needed | | Customer support vendors | Basic, Communication Information | | Payment processors | Basic, Financial Information | | Market data providers | Trading, Usage Information | | Technology infrastructure providers | All categories as needed | | Clearing and settlement providers | Trading, Financial Information | ### Legal and Regulatory Sharing We may share your information: * To comply with legal or regulatory requests * To detect, investigate, or prevent fraud * To protect QFEX, users, and the public * In connection with legal disputes or market surveillance ### Business Transfers If QFEX undergoes a merger, acquisition, or restructuring, personal data may be transferred as part of that transaction. ## 4. How Long We Retain Your Personal Information We retain data for as long as necessary to: * Operate our platform, * Comply with legal and regulatory obligations (e.g., Investment Business Act), * Prevent fraud and ensure security, * Maintain required trading and transaction records. When you close your account or request deletion, we remove unnecessary data, retaining only what is required by law or regulation. ## 5. Children's Personal Information Our platform is **not directed to individuals under 18**.\ If we discover that someone under 18 has provided personal information, we will delete it promptly and close any related accounts. ## 6. Your Privacy Rights and Choices Depending on your jurisdiction, you may have the following rights: * **Access** – Request a copy of your information * **Rectification** – Correct inaccurate or incomplete information * **Deletion** – Request deletion of your data * **Restriction** – Limit how we process your information * **Objection** – Object to processing based on legitimate interest * **Portability** – Request a portable copy of your data * **Withdraw Consent** – Withdraw consent for optional processing You can exercise these rights via your account settings or by contacting **[privacy@qfex.com](mailto:privacy@qfex.com)**. ### Informational Communications You may opt out by: * Adjusting account settings * Using unsubscribe links in emails * Contacting support ## 7. Data Security We use technical and organizational safeguards to protect your personal information, including: * Encryption of sensitive data * Access controls and authentication * Regular security audits and risk assessments * Employee training in data protection * Incident response procedures * Secure infrastructure and MFA * Continuous monitoring and threat detection > ⚠️ No system is 100% secure. However, QFEX maintains rigorous standards to minimize risk. ## 8. Changes to This Privacy Policy We may update this Privacy Policy periodically.\ You will be notified of material changes via: * Updates on our website * Email notifications * Notices within our trading platform **Last updated date:** displayed at the top of this document. ## 9. How to Contact Us If you have any questions about this Privacy Policy or our data practices, please contact us: **Email:** [privacy@qfex.com](mailto:privacy@qfex.com) # Waitlist Agreement Source: https://docs.qfex.com/legal/waitlist-agreement Last Updated: 28 November 2025 ### Important Notice These Waitlist and Referral Program Terms and Conditions ("Terms") constitute a legally binding agreement between you ("you," "your," or the "User") and QFEX Inc. ("QFEX," "we," "us," or "our"). **PLEASE READ THESE TERMS CAREFULLY BEFORE PARTICIPATING IN THE PROGRAM**. By clicking "I AGREE" or by participating in the Program, you acknowledge that you have read, understood, and agree to be bound by these Terms. If you do not agree with these Terms, you must not participate in the Program. These Terms govern your participation in the Program only. They do not govern the use of any QFEX trading services. When trading becomes available to you, you will be required to agree to separate terms and conditions before you can open a trading account and access our services. *** ### 1. Definitions For purposes of these Terms, the following definitions apply: * **"Account"**: means your QFEX waitlist account created to participate in the Program. * **"Affiliate"**: means, with respect to any person, any other person that directly or indirectly controls, is under common control with, or is controlled by, such person. * **"Applicable Law"**: means any domestic or foreign law, rule, statute, regulation, by-law, order, protocol, code, decree, or other directive, requirement or guideline, published or in force which applies to or is otherwise intended to govern or regulate any person, property, transaction, activity, event or other matter, including any rule, order, judgment, directive or other requirement or guideline issued by any domestic or foreign federal, provincial, state, municipal or local government, regulatory authority, government department, agency, commission, bureau, minister, court or other law, rule or regulation-making entity having jurisdiction over QFEX, you, or as otherwise duly enacted, enforceable by law, the common law or equity. * **"Financial Instruments"**: means securities, derivatives, commodities, currencies, and other financial products that may be traded on the Platform. * **"Platform"**: means the QFEX financial exchange platform to be granted access to in the future. * **"Program"**: means the QFEX waitlist and referral program described in these Terms. * **"Prohibited Persons"**: means: * (a) a person or entity listed on any of the Restricted Persons Lists (defined below); * (b) a person or entity who is located, organized or resident in a country or territory that is, or whose government is, the subject of Sanctions; * (c) a person or entity who is located, organized or resident in any of the following countries: the United States, France, Cuba, Iran, Russia, North Korea, Sudan, Spain, the United Kingdom, Myanmar, Venezuela, or the territories of Luhansk and Donetsk; * (d) a person or entity otherwise prohibited by Applicable Law from accessing or using the Program. * **"Restricted Persons Lists"**: means: * (a) the Specially Designated Nationals and Blocked Persons List and the Sectoral Sanctions Identification List maintained by the U.S. Treasury Department's Office of Foreign Assets Control; * (b) the Denied Persons List, Entity List, and Unverified List maintained by the U.S. Commerce Department's Bureau of Industry and Security; * (c) the non-proliferation sanctions lists maintained by the U.S. State Department; * (d) the United Nations Security Council Consolidated List; * (e) the Consolidated List of Financial Sanctions Targets maintained by the UK Treasury; * (f) similar lists maintained by the European Union; and * (g) any other list of restricted persons maintained under Sanctions. * **"Sanctions"**: means economic sanctions, trade embargoes, export or import controls, anti-boycott, and anti-money laundering laws, including those administered, enacted or enforced by: * (a) the United States, including the U.S. Treasury Department (including the Office of Foreign Assets Control), the U.S. Commerce Department (including the Bureau of Industry and Security), or the U.S. State Department; * (b) the United Nations; * (c) the European Union; * (d) the United Kingdom; * (e) any other relevant sanctions authority. * **"Waitlist"**: means the pre-launch registration system that allows prospective users to register their interest in the Platform. *** ### 2. Eligibility and Account Creation #### 2.1 Eligibility Requirements To participate in the Program, you represent and warrant that: * (a) **Age and Capacity**: You are at least eighteen (18) years of age and have the full right, power, capacity and authority to enter into and perform your obligations under these Terms; * (b) **Legal Standing**: You are not a Prohibited Person and will not use the Program if the laws of your country, or any other Applicable Law, prohibit you from doing so in accordance with these Terms; * (c) **Compliance**: Your participation in the Program will not violate any and all laws, rules, regulations, ordinances, directives, acts, or requirements of any applicable jurisdiction; * (d) **Accuracy**: All information you provide to us is truthful, accurate, current, and complete, and you agree to maintain and update such information to keep it truthful, accurate, current, and complete; * (e) **Single Account**: You will maintain only one Account and will not create additional Accounts or share your account with others; * (f) **No Prohibited Activities**: You will not use the Program for any illegal activity or to violate any Applicable Law. #### 2.2 Prohibited Jurisdictions The Program is not available to residents of certain jurisdictions. You may not participate in the Program if you are located in, organized in, or a resident of: * (a) Any jurisdiction where the Program would be illegal or require registration, licensing, or authorization that we have not obtained; * (b) Any jurisdiction listed in the definition of Prohibited Persons above. #### 2.3 Account Creation and Verification * (a) **Registration**: To create an Account, you must provide accurate and complete information as requested in our registration process. * (b) **Identity Verification**: We may require you to complete identity verification procedures, including providing government-issued identification documents and other information as we may reasonably request. * (c) **Enhanced Due Diligence**: We reserve the right to require enhanced due diligence procedures for any user, including additional documentation and information. * (d) **Ongoing Monitoring**: We may monitor your Account and activities for compliance with these Terms and Applicable Law. *** ### 3. Waitlist and Referral Program #### 3.1 Waitlist Participation * (a) **Purpose**: The Waitlist allows you to register your interest in accessing the Platform when it becomes available. * (b) **No Guarantee**: Participation in the Waitlist does not guarantee access to the Platform or any particular position in any launch queue. * (c) **No Financial Services**: The Waitlist does not involve the provision of any financial services, investment advice, or custody of assets. * (d) **Discretionary Access**: We reserve the right to grant or deny access to the Platform in our sole discretion, subject to Applicable Law. #### 3.2 Referral Program Mechanics Upon joining the Waitlist, you may participate in our referral program by: * (a) **Sharing Referral Links**: Using your unique referral link to invite others to join the Waitlist; * (b) **Profile Enhancement**: Uploading a profile picture to your Account; * (c) **Security Setup**: Enabling two-factor authentication (2FA) on your Account. #### 3.3 Referral Program Rules * (a) **Legitimate Referrals**: All referrals must be legitimate and made to real persons who are eligible to participate in the Program. * (b) **No Self-Referrals**: You may not refer yourself or create multiple Accounts to generate referrals. * (c) **No Spam**: You may not send unsolicited communications or engage in spamming activities. * (d) **Compliance**: All referral activities must comply with Applicable Law, including anti-spam and privacy laws. * (e) **Modification**: We reserve the right to modify, suspend, or terminate the referral program at any time without notice. * (f) **Rewards**: Rules for the calculation of referral rewards can be found at **docs.qfex.com**. *** ### 4. Prohibited Activities You agree that you will not use the Program to: * (a) **Violate Laws**: Violate any Applicable Law, including but not limited to anti-money laundering, counter-terrorist financing, privacy, data protection, consumer protection, or market manipulation laws; * (b) **Infringe Rights**: Infringe or violate the intellectual property rights or any other rights of third parties; * (c) **Engage in Fraud**: Engage in any fraudulent, deceptive, or manipulative activities; * (d) **Harm Systems**: Interfere with, disrupt, negatively affect, or inhibit other users from enjoying the Program, or damage, disable, overburden, or impair the functioning of the Program; * (e) **Unauthorized Access**: Attempt to circumvent any content-filtering techniques we employ, or attempt to access areas or features of the Program that you are not authorized to access; * (f) **Reverse Engineer**: Reverse engineer, decompile, disassemble, or otherwise attempt to derive the source code of the Program; * (g) **Create Multiple Accounts**: Create or maintain more than one Account; * (h) **Use Automated Systems**: Use any robot, spider, crawler, scraper, or other automated means or interface to access the Program or extract data; * (i) **Market Manipulation**: Engage in any activity that could manipulate or artificially affect the referral program or Waitlist positions. *** ### 5. Privacy and Data Protection #### 5.1 Privacy Policy Your privacy is important to us. Our collection, use, and disclosure of your personal information is governed by our [Privacy Policy](https://docs.qfex.com/legal/privacy-policy), which is incorporated by reference into these Terms. By participating in the Program, you consent to the collection, use, and disclosure of your personal information in accordance with our [Privacy Policy](https://docs.qfex.com/legal/privacy-policy). #### 5.2 Communications Consent By creating an Account, you consent to receive electronic communications from us, including: * (a) Transactional communications related to your Account and the Program; * (b) Informational communications about our services, industry developments, and educational content; * (c) Legal notices and updates to these Terms or other policies. You may opt out of informational communications as described in our Communications Policy, but you cannot opt out of transactional communications. *** ### 6. Intellectual Property #### 6.1 Our Rights The Program and all materials therein, including but not limited to software, images, text, graphics, logos, patents, trademarks, service marks, copyrights, photographs, audio, videos, and music (the "QFEX Content"), are owned by or licensed to us and are protected by copyright, trademark. #### 6.2 Limited License Subject to your compliance with these Terms, we grant you a limited, non-exclusive, non-transferable, non-sublicensable, revocable license to access and use the Program for your personal, non-commercial use only. #### 6.3 Restrictions You may not: * (a) Copy, modify, distribute, sell, or lease any part of the Program or QFEX Content; * (b) Reverse engineer or attempt to extract the source code of the Program; * (c) Use the Program or QFEX Content for any commercial purpose without our express written consent. *** ### 7. Disclaimers #### 7.1 No Warranties THE PROGRAM IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT. WE DO NOT WARRANT THAT THE PROGRAM WILL BE UNINTERRUPTED, ERROR-FREE, OR FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS. #### 7.2 No Investment Advice WE DO NOT PROVIDE INVESTMENT, LEGAL, TAX, OR FINANCIAL ADVICE. ANY INFORMATION PROVIDED THROUGH THE PROGRAM IS FOR INFORMATIONAL PURPOSES ONLY AND SHOULD NOT BE CONSTRUED AS INVESTMENT, LEGAL, TAX, OR FINANCIAL ADVICE. #### 7.3 Limitation of Liability TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL QFEX, ITS AFFILIATES, OR THEIR RESPECTIVE OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, OR REPRESENTATIVES BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, USE, GOODWILL, OR OTHER INTANGIBLE LOSSES, ARISING OUT OF OR RELATING TO YOUR PARTICIPATION IN THE PROGRAM, REGARDLESS OF THE THEORY OF LIABILITY AND EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #### 7.4 Cap on Liability TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, OUR TOTAL LIABILITY TO YOU FOR ALL CLAIMS ARISING OUT OF OR RELATING TO THESE TERMS OR THE PROGRAM SHALL NOT EXCEED **TEN DOLLARS (\$10)**. *** ### 8. Indemnification You agree to indemnify, defend, and hold harmless QFEX, its Affiliates, and their respective officers, directors, employees, agents, and representatives from and against any and all claims, damages, losses, costs, and expenses (including reasonable attorneys' fees) arising out of or relating to: * (a) Your breach of these Terms; * (b) Your violation of any Applicable Law; * (c) Your violation of any rights of third parties; * (d) Your use of the Program. *** ### 9. Termination #### 9.1 Termination by You You may terminate your participation in the Program at any time by deleting your Account through the Program interface or by contacting us. #### 9.2 Termination by Us We may terminate or suspend your Account and participation in the Program immediately, without prior notice or liability, for any reason, including but not limited to: * (a) Breach of these Terms; * (b) Violation of Applicable Law; * (c) Fraudulent, abusive, or illegal activity; * (d) Extended periods of inactivity; * (e) Our decision to discontinue the Program. #### 9.3 Effect of Termination Upon termination: * (a) Your right to participate in the Program will cease immediately; * (b) We may delete your Account and all associated data; * (c) Sections that by their nature should survive termination shall survive, including but not limited to intellectual property, disclaimers, limitation of liability, indemnification, and governing law provisions. *** ### 10. Dispute Resolution #### 10.1 Governing Law These Terms and any dispute or claim arising out of or in connection with them shall be governed by and construed in accordance with the laws of **Panama**, without regard to conflict of law principles. #### 10.2 Arbitration If a complaint cannot be resolved through QFEX’s internal process, the matter (“Dispute”) shall be referred to **binding arbitration** under the Rules of Arbitration of the International Chamber of Commerce (ICC) then in effect. * (a) The seat of arbitration shall be **Panama City, Republic of Panama**. * (b) The arbitration shall be conducted in English. * (c) The tribunal shall consist of one (1) arbitrator appointed in accordance with ICC rules. * (d) The decision of the arbitrator shall be final and binding upon both parties. #### 10.3 Class Action Waiver YOU AGREE THAT ANY ARBITRATION OR PROCEEDING SHALL BE LIMITED TO THE DISPUTE BETWEEN US AND YOU INDIVIDUALLY. TO THE FULLEST EXTENT PERMITTED BY LAW, YOU AGREE THAT: * (A) NO ARBITRATION OR PROCEEDING SHALL BE JOINED WITH ANY OTHER; * (B) THERE IS NO RIGHT OR AUTHORITY FOR ANY DISPUTE TO BE ARBITRATED OR RESOLVED ON A CLASS-ACTION BASIS OR TO UTILIZE CLASS ACTION PROCEDURES; * (C) THERE IS NO RIGHT OR AUTHORITY FOR ANY DISPUTE TO BE BROUGHT IN A PURPORTED REPRESENTATIVE CAPACITY ON BEHALF OF THE GENERAL PUBLIC OR ANY OTHER PERSONS. *** ### 11. General Provisions #### 11.1 Entire Agreement These Terms, together with our [Privacy Policy](https://docs.qfex.com/legal/privacy-policy), [Cookie Policy](https://docs.qfex.com/legal/cookie-policy), and other policies referenced herein, constitute the **entire agreement** between you and us regarding the Program and supersede all prior agreements, understandings, and representations. #### 11.2 Amendment We may amend these Terms from time to time by posting the amended Terms on our website. Material changes will be effective thirty (30) days after posting, unless we specify a different effective date. Your continued participation in the Program after the effective date constitutes acceptance of the amended Terms. #### 11.3 Severability If any provision of these Terms is found to be invalid, illegal, or unenforceable, the remaining provisions shall continue in full force and effect, and the invalid, illegal, or unenforceable provision shall be deemed modified to the minimum extent necessary to make it valid, legal, and enforceable. #### 11.4 No Waiver No failure or delay by us in exercising any right or remedy under these Terms shall operate as a waiver of that right or remedy, nor shall any single or partial exercise preclude any other or further exercise. #### 11.5 Assignment You may not assign or transfer your rights or obligations under these Terms without our prior written consent. We may assign or transfer our rights and obligations under these Terms without restriction, including in connection with a merger, acquisition, or sale of assets. #### 11.6 Force Majeure We shall not be liable for any failure or delay in performance under these Terms due to causes beyond our reasonable control, including but not limited to acts of God, war, terrorism, epidemics, government actions, or technical failures. #### 11.7 Relationship Nothing in these Terms creates any agency, partnership, joint venture, or employment relationship between you and us. #### 11.8 Contact Information QFEX Inc. is a company incorporated under the laws of the **Republic of Panama** with its registered office located at Office 317, Vía Ricardo J. Alfaro, PH The Century Tower, Betania, Panama, Panamá, Panama, 07095. If you have any questions about these Terms, please contact us at: * Email: **[legal@qfex.com](mailto:legal@qfex.com)** # About QFEX Source: https://docs.qfex.com/qfex/about How Markets Should Be # What is QFEX? QFEX is the first hybrid perpetual futures exchange to allow **high leverage, performant trading on traditional financial assets**. Markets on QFEX operate 24/7 like crypto venues, with external market makers, allowing users to trade outside of market hours. QFEX utilizes a Central Limit Order Book, or ‘CLOB’, and maintains CEX-like features such as **microsecond-level latency, native fiat and crypto payment rails, anti-HFT arbitrage protections and circuit breakers**. In the long-term, QFEX aims to replace the entire \$100bn TradFi exchange, clearing and brokerage industry, with an ambition to be the trading exchange of choice for global banks, hedge funds and family offices, offering 24/7 access to a huge range of assets, both traditional and complex. # Who is the team? QFEX was founded by Cambridge mathematicians [Annanay Kapila](https://x.com/annanay) and [Joshua Wharton](https://x.com/joshuawharton). Annanay was previously one of the first members of [Flow Traders'](https://www.flowtraders.com) crypto team, and then a Quant at [Tower Research Capital](https://tower-research.com/), where he was responsible for double digit market share across all major crypto venues. Josh was an Engineer at [Citadel](https://www.citadel.com/). The rest of the team comes from [Jump](https://jumptrading.com), [HRT](https://www.hudsonrivertrading.com/), [Jane Street](https://janestreet.com), [Optiver](https://optiver.com), [SIG](https://sig.com) and more. # Who are your backers? QFEX has raised money exclusively from Silicon Valley VC firms, including General Catalyst and Y Combinator. # Exchange Source: https://docs.qfex.com/qfex/architecture Technical Description of the Exchange ## Exchange Architecture QFEX operates as a Central Limit Order Book (“CLOB”) exchange, aggregating all buy and sell orders into a single transparent order book that displays the best available prices and quantities to all participants simultaneously. Orders are executed based on strict price-time priority rules, ensuring that the best-priced orders execute first, and among orders at the same price, those received earlier have priority (subject to a speed bump which is implemented to protect against latency arbitrage - see below). This architecture provides price transparency, guarantees fair execution, and promotes efficient price discovery by bringing all market participants together in a single venue. The exchange code is written primarily in Rust and runs on Amazon Web Services hosted in Tokyo. Both market data and order entry access is via GUI and API (websockets), with equal access on all terms for all clients. ## Speed Bump Implementation QFEX implements a 100-millisecond speed bump on all limit orders to protect against latency arbitrage and create a level playing field for all participants. When a limit order is received, it is held in a queue before being sent to the order book. This delay applies uniformly regardless of the participant's technological sophistication or network connectivity. The speed bump applies to all limit orders including new submissions and modifications, but not to any other request. This implementation reduces advantages gained through technological superiority alone and encourages broader market participation, typically leading to improved liquidity and more efficient price discovery. It is in line with standard industry practice to create a fair market place, and encourage the provision of liquidity. ## Self-trade Prevention Traders may not self-trade on QFEX. In the event of two orders from the same trader matching, the passive order will be canceled. # Bank Transfer Source: https://docs.qfex.com/qfex/bank-transfer Pay via Bank Transfer We support bank transfer funding in USD. Transfers must be domestic. ## Deposits * ACH deposit available (USD only). * Processing time: 1-3 business days. ### How To Deposit USD 1. Open **Deposit / Withdraw** from your account header. 2. Select **Deposit funds**. 3. Choose **USD** to continue with bank transfer funding. ## Withdrawals * ACH withdrawal: 0.1% fee + \$1. * Wire withdrawal: 0.1% fee + \$10. * Processing time (standard): ACH 1-3 business days; wire same day to 1 business day. # Contract Specifications Source: https://docs.qfex.com/qfex/contract-specifications Perpetual Futures Adapted for Traditional Assets ## What are QFEX Perpetual Futures? A perpetual future is a derivative contract that allows you to speculate on the price of an underlying asset without ever having to physically own it. Unlike traditional futures contracts, **perpetuals do not have an expiry date**. You can hold a position for as long as you like, provided you maintain sufficient margin. Perps are the end state of leveraged finance. They are the most efficient and user-friendly way of trading all manner of asset classes. To ensure the price of the perpetual contract (Mark Price) stays close to the spot price of the underlying asset (Index Price), a mechanism called **Funding** is used. All QFEX Perpetual Futures are margined in [USDC](https://www.circle.com/usdc) on Arbitrum. USDC is compliant with [US Law](https://en.wikipedia.org/wiki/GENIUS_Act) and backed by [US Treasuries](https://www.circle.com/transparency). ## Index Price Sources The Index Price is the reference spot price for the asset. We aggregate data from high-quality sources: * **Equities:** Real-time feeds from US stock exchanges. * **Indices:** Derived from futures data. * **FX & Precious Metals:** An aggregate of the most liquid ECNs. ## Oracle Pricing Our *default pricing* is: For non-equity indices: $$ P_t^{\text{oracle}} = P_t^{\text{index}} $$ For equity indices: $$ P_t^{\text{oracle}} = P_{\text{last close}}^{\text{equity index}} + \Delta F_t $$ where $\Delta F_t$ is the corresponding change in the equity index future. ## Futures-Based Oracle Rolls Some QFEX products derive oracle pricing from a dated futures contract and therefore roll from one contract month to the next on the published [Roll Schedules](/qfex/roll-schedules). For `CL-USD`, `COPPER-USD`, and `NATGAS-USD`, the contract blend shifts by 20 percentage points at each of the final five CME business-day boundaries before the roll completes. The [Roll Schedules](/qfex/roll-schedules) page contains the exact weights and published contract boundaries. Use `GET /settlement-calendar` to resolve the active dated future for a supported QFEX symbol. The response returns: * `future_symbol`: the futures contract currently used by the oracle. * `active_until`: the last timestamp at which that contract remains active for the QFEX symbol. * `expiration`: the expiration timestamp of that dated future. If `time` is omitted, the endpoint returns the currently active contract. For live integrations, use the QFEX settlement calendar endpoint rather than hardcoding roll dates. If the last known Index Price is *stale* (ie, the market is closed or otherwise down), we do the following: ### 1. Impact Notional Calculation The system calculates the Volume-Weighted Average Price (VWAP) to fill a specific "Impact Notional" amount (defined below) from the top of the order book. * **Impact Bid**: The average price to sell the impact notional amount into the bids. * **Impact Ask**: The average price to buy the impact notional amount from the asks. ### 2. Impact Price Deviation (IPD) IPD measures the pressure on the price relative to the *last traded price* (or last calculated price). It is calculated as: $$ IPD = \max(ImpactBid - P_{last}, 0) - \max(P_{last} - ImpactAsk, 0) $$ Where: * $P_{last}$ is the latest Index price. * Only "improving" deviations contribute to the IPD (i.e., if the Impact Bid is higher than current price, it pushes price up; if Impact Ask is lower, it pushes price down). ### 3. Price Update The price is updated using an Exponential Moving Average (EMA) model to smooth out volatility while drifting towards the order book pressure. The formula used is: $$ S_t = \beta_t \cdot S_{t-1} + (1 - \beta_t) \cdot x_t $$ Where: * $S_t$: New price. * $S_{t-1}$: Previous price. * $x_t$: Target price based on IPD, defined as $x_t = S_{t-1} + IPD_t$. * $\beta_t$: Decay factor, defined as $\beta_t = e^{-\Delta t^* / \tau}$. #### Time and Constants * **$\tau$ (Tau)**: Time constant, set to **30 minutes** (`1800` seconds). This controls the "inertia" of the price. * **$\Delta t$**: Time elapsed since the last update. * **$c$ (Clamp Factor)**: Set to **0.1**. * **$\Delta t^*$**: Clamped time delta, defined as $\min(\Delta t, c \cdot \tau)$. This prevents large jumps if updates are sparse. # Corporate Actions Source: https://docs.qfex.com/qfex/corporate-actions QFEX Policy on Equity Corporate Actions ## Overview Corporate actions are events initiated by a public company that affect the securities (equity or debt) issued by that company. For users familiar with crypto markets: * **Dividends** are analogous to **airdrops** or **staking rewards**. * **Stock Splits** are similar to **token re-denominations** (like the DOT split). ## General Policy QFEX **does not adjust** positions or margin for most corporate actions, including cash dividends. We rely on the efficient market hypothesis: the **market prices in** these events. The impact of a corporate action is naturally reflected in the Mark Price as traders adjust their valuations leading up to the event. ## Stock Splits and Reverse Splits Exceptions are made for stock splits and reverse stock splits to ensure position continuity and accurate PnL tracking. ### The Procedure When a stock split or reverse split occurs, QFEX executes the following process: 1. **Trading Halt**: Trading is suspended at the close of the post-market session on the day before the split effective date. 2. **PnL Realization**: All open positions have their PnL realized (settled) at the last known Mark Price. 3. **Re-opening**: Positions are immediately re-opened with adjusted parameters: * **Quantity**: Multiplied (or divided) by the split ratio. * **Mark Price / Entry Price**: Divided (or multiplied) by the split ratio. This mechanism ensures that the **notional value** of your position remains neutral across the split, preventing artificial liquidation or profit spikes. # Definitions and Formulae Source: https://docs.qfex.com/qfex/definitions Common Terms Used in the Rulebook ### Market Data Price The price of the underlying asset, derived from the relevant external oracle source.\ Denoted as $P_t^{\text{market}}$. ### Index Price When the current market price stays within the allowed band, the index price is: $$ P_t^{\text{index}} = P_t^{\text{market}} $$ when $$ P_t^{\text{market}} \in [0.5 P_{t-1}^{\text{market}},\; 1.5 P_{t-1}^{\text{market}}] $$ Otherwise, the index price is held at the prior market price: $$ P_t^{\text{index}} = P_{t-1}^{\text{market}} $$ That is, the Index Price equals the current Market Data Price if it lies within ±50% of the previous value, otherwise the prior price is used. ### Oracle Price Defined in [Contract Specifications](/qfex/contract-specifications): ### Mark Price The Mark Price $P_t^{\text{mark}}$ is computed as: $$ P_t^{\text{mark}} = \text{Median} \Big( P_t^{\text{oracle}},\; P_t^{\text{oracle}} + \text{EMA}_{150s}(M_t - P_t^{\text{oracle}}),\; \text{Median}(B_t,\; A_t,\; T_t) \Big) $$ where $M_t$ is the mid price, $B_t$ the best bid, $A_t$ the best ask, and $T_t$ the last traded price. ### Unrealized PnL $$ PnL_{\text{unrealized}} = \sum_i q_i \cdot (P_t^{\text{mark}} - P_{i,\text{entry}}) $$ for all open positions $i$ with quantity $q_i$. ### Realized PnL $$ PnL_{\text{realized}}= \sum_j (P_{j,\text{exit}} - P_{j,\text{entry}}) \cdot q_j $$ for all closed positions $j$. ### Cash $$ \text{Cash} = D - W + F_{\text{net}} + RR - \text{Fees} $$ where $D$ = deposits, $W$ = withdrawals, $F_{\text{net}}$ = net funding, $RR$ = referral rewards. ### Margin $$ \text{Margin} = \text{Position Margin} + \text{Order Margin} $$ ### Account Equity $$ \text{Equity} = \text{Cash} + PnL_{\text{realized}} + PnL_{\text{unrealized}} $$ ### Available Balance $$ \text{Available Balance} = \text{Account Equity} - \text{Margin} $$ ### Withdrawable Balance $$ \text{Withdrawable Balance} = \text{Cash} + PnL_{\text{realized}} + \min(PnL_{\text{unrealized}}, 0) - 1.05 \times \text{Margin} $$ ### Position Value $$ V = P_t^{\text{mark}} \times Q $$ where $Q$ is the position quantity in the symbol. ### Funding Rate The rate $r_t^{\text{funding}}$ paid between long and short positions when the futures price deviates from the underlying index. ### Funding Fee $$ \text{Funding Fee} = P_t^{\text{mark}} \times Q \times r_t^{\text{funding}} $$ ### Liquidation Spread The maximum spread $\Delta_{\text{liq}}$ from $P_t^{\text{mark}}$ at which an orderly **Immediate-or-Cancel (IOC)** liquidation order is executed. ### DLP Fee A fee $f_{\text{DLP}}$ paid to **Designated Liquidity Providers (DLPs)** who absorb liquidated positions. ### Mark-to-Market (MTM) All portfolios are re-evaluated every **200 ms** using the Mark Price $P_t^{\text{mark}}$ to: * Recalculate Unrealized PnL, * Detect margin requirement breaches, * Trigger liquidation procedures. # FAQ Source: https://docs.qfex.com/qfex/faq Frequently Asked Questions #### What is QFEX? QFEX is the first traditional assets exchange to offer high leverage, 24/7 trading of perpetual futures. #### How do I join QFEX? QFEX is invite-only for now. To join, you need a valid invitation code from an existing QFEX user. #### What is QFEX's mission? QFEX aims to bring its proprietary, innovative exchange and risk infrastructure design to allow capital-efficient trading of futures even when the underlier is closed. In the long-term, QFEX aims to replace the entire \$100bn exchange, clearing and brokerage industry, with an ambition to be the trading exchange of choice for global banks, institutions and hedge funds, offering 24/7 access to a deep liquidity pool on a huge range of assets. #### Why are current tradfi exchanges broken? Modern market structure is still led by the Commodites Exchange Act in the US, which ultimately optimized for midwestern farmers. These farmers want expiries and don't care about leverage so much. The vast majority of futures volume now is done by speculators and institutions seeking efficiency. The products that have to cater to them and comply with the CFTC's idea of a fair market - like ES or GC - are missing the point. People don't want expiry; they want leverage, they want instant settlements, they want 24/7 access. #### What are the biggest architectural constraints in the traditional model? Intermediation. Traditional exchanges developed in a haphazard way, when the physical nature of brokers (pit traders), clearers (accountants) and exchanges (a physical pit) were totally different. Now, they are all software, and therefore capable of integration. Intermediation prevents true capital efficiency, adds cost and makes 24/7 operation extremely difficult. #### What are perpetuals and why are they different to futures? Perps were made popular by Bitmex, but are not necessarily anything to do with crypto. If you forget about calendar futures, perps are the natural way to facilitate trading with leverage. If you want to compare them to expiring futures, imagine an 8-hourly future that rolls without any cost. Why would you have a future expiring anyway? The answer is if the expiry corresponds to something - like the harvest of a crop, or arrival time of an oil tanker. This use case is now a minuscule fraction of futures trading volume. ### What charting do you use? The charting technology of QFEX is powered by TradingView, the most reputable platform offering advanced charts, a [stock screener](https://www.tradingview.com/screener/) and other features. #### How is QFEX different to a CFD platform? QFEX removes the broker from trading – brokers can increase costs for investors (by widening the spread), and manipulate the market, like by hunting for your stop losses. With QFEX, traders and investors can become the broker, able to set prices themselves and not rely on a market-maker. #### How do you incorporate dividends and other corporate actions? Dividends etc are handled much in the same way they are handled in crypto perps (eg, dividends are just handled by market makers), as all of these things have an analog in the crypto world (eg airdrops, hard forks etc). #### Does QFEX have LULD bounds and circuit breakers? LULD is an unsatisfactory way to slow down disorderly trading in equities. We follow the 'futures paradigm' of price limits at a fixed width around the last known underlier price. If the underlying equities hit a volatility stop, we will still allow trading around the last known price before the stop. The funding will be 'marked' to that last price, so people will have to pay funding in order to trade away from this price. #### What about tokenized equities? Tokenized equities and equity perps can exist side-by-side as they serve different use cases, as in all spot and derivatives markets (trading/ hedging vs long-term investing). The incremental value add of tokenizing equities vs holding the equities themselves is very low, and offset by blockchain security issues. QFEX concentrates solely on perps. #### Do you have historical data? Historical data will be available for download soon. #### What kinds of market maker protections do you offer? * A 500ms speed bump on limit orders to prevent latency arbitrage (cancels and liquidity-adding orders are not affected). * A sensible tick-size regime for our products, re-evaluated weekly. #### How are your funding rates computed? Our funding formula is modelled on Binance's, with three notable differences: * Funding is computed and paid every 1 hour, not 8 hours. * There is no 1 basis point bias in the formula. * The final funding rate is scaled by `1/100` after the premium/deadband step. For full details on funding hours, why funding can be `0`, and calculation logic, see [Funding](https://docs.qfex.com/qfex/funding). Formula details are also available in [Contract Specifications](https://docs.qfex.com/qfex/contract-specifications). #### What are the restricted locations? Due to legal and regulatory reasons in certain major jurisdictions, we currently ban the onboarding of new users from many countries and locations, including but not limited to the following: * United States * United Kingdom * France * Spain * Ukraine * Syria * Iran * Russia * North Korea * Myanmar * Belarus * Venezuela * Sudan #### What products do you offer? We are rolling out USDC-margined perpetual futures across large cap US equities, indices, commodities and FX. For the latest product set, always refer to the [Trading UI](https://qfex.com/trade). # Fees Source: https://docs.qfex.com/qfex/fees QFEX uses a maker-taker fee model for determining its trading fees. Orders that provide liquidity (maker orders) are charged different fees than orders that take liquidity (taker orders). Fees are calculated based on the current pricing tier you are in when the order is placed, and not on the tier you would be in after a trade is completed. Your fee tier is based upon total USD trading volume over the trailing 30 day period. Transactions made on books quoted in USD, e.g. EUR-USD, are counted as the total USD amount of each filled order. When you place an order at the market price that gets filled immediately, you are considered a taker and will pay a fee between 0.006% and 0.10%. When you place an order which is not immediately matched by an existing order, that order is placed on the order book. If another customer places an order that matches yours, you are considered the maker and will pay a fee between 0.00% and 0.10%. When you place an order that gets partially matched immediately, you pay a taker fee for that portion. The remainder of the order is placed on the order book and, when matched, is considered a maker order. You pay a maker fee for this remaining portion of the total order. Please note that the pricing tiers can take some time to update. For future orders, we recommend checking your fee tier before you trade to ensure you are in the updated pricing tier. There are five tiers of fees, based on your Effective Volume for a trailing 30-day period traded on the platform. Effective Volume is calculated as follows: $$ \text{Effective Volume} = 1 \times \text{FX} + 2 \times \text{Commodities} + 2 \times \text{Indices} + 5 \times \text{Single stocks} $$ Where: * FX = volume traded against FX futures (eg EUR/USD) * Commodities = volume traded against commodities futures (eg Gold) * Indices = volume traded against equity index futures (eg US100) * Single stocks = volume traded against single stock futures (eg PLTR) | Taker fees (%) / Tier | Effective Volume (volume traded on the platform in last 30 days) | FX | Commodities | Indices | Single stocks | | :-------------------- | :--------------------------------------------------------------- | ------- | ----------- | ------- | ------------- | | Tier 5 | \<2m\$ | 0.02% | 0.05% | 0.05% | 0.10% | | Tier 4 | \$2m - \$10m | 0.015% | 0.04% | 0.04% | 0.08% | | Tier 3 | \$10m - \$100m | 0.01% | 0.02% | 0.02% | 0.05% | | Tier 2 | \$100m - \$400m | 0.0075% | 0.01% | 0.01% | 0.02% | | Tier 1 | \$400m+ | 0.006% | 0.006% | 0.006% | 0.015% | | Maker fees (%) / Tier | Effective Volume (volume traded on the platform in last 30 days) | FX | Commodities | Indices | Single stocks | | :-------------------- | :--------------------------------------------------------------- | ------- | ----------- | ------- | ------------- | | Tier 5 | \<2m\$ | 0.01% | 0.02% | 0.02% | 0.05% | | Tier 4 | \$2m - \$10m | 0.0075% | 0.015% | 0.015% | 0.04% | | Tier 3 | \$10m - \$100m | 0.005% | 0.01% | 0.01% | 0.025% | | Tier 2 | \$100m - \$400m | 0.0025% | 0.005% | 0.005% | 0.01% | | Tier 1 | \$400m+ | 0% | 0% | 0% | 0% | # Funding Source: https://docs.qfex.com/qfex/funding When funding is active, why it can be zero, and how rates are computed. Funding keeps perpetual prices anchored to their underlier. QFEX supports 24/7 trading, but funding is only active when we can reliably consume underlier prices from primary venues. ## At a Glance * Funding is calculated and settled every **60 minutes**. * Funding is only active during a symbol's configured `market_hours`. * Outside those hours, funding rate is **`0`** and no funding payment is exchanged. * The live websocket `funding` stream shows the **current implied final rate** if the current window ended now. ## Funding Hours (Current) | Markets | Underlier venue/source | Funding-active hours | | -------------------------------------- | ------------------------- | ------------------------------------------------------------ | | Most USD equities | US securities exchanges | Sunday 20:00–Friday 20:00 ET | | Korean equities | Korea Exchange | Weekdays 09:00–15:30 KST | | `SIVE-SEK` | Nasdaq Stockholm | Weekdays 09:00–17:00 Europe/Stockholm | | `GOLD-USD` and `SILVER-USD` | Relevant metals venues | Sunday 17:00–Friday 17:00 ET | | `CL-USD`, `US100-USD`, and `US500-USD` | US futures exchanges | Sunday 17:00–Friday 16:00 CT, with a daily 16:00–17:00 pause | | Other active commodities and indices | Relevant reference venues | Sunday 17:00–Friday 20:00 ET | See the [Specification Index](/qfex/specification-index) for the consolidated per-symbol schedule. ## Per-Symbol Funding Hours in Refdata Always use refdata as the source of truth for symbol-specific funding hours: * REST: `https://api.qfex.com/refdata`, docs [here](/websocket/channels/mds/refdata) Look at the `market_hours` object for each symbol. ```json theme={null} { "symbol": "AAPL-USD", "market_hours": { "tz": "America/New_York", "monday": [ { "open": "00:00:00", "close": "23:59:59", "session": "open" } ] } } ``` ## Methodology Our calculation methodology closely follows the industry standard, with simplified parameters for greater transparency and efficiency. **Key Parameters:** * **Funding Interval:** Every **60 minutes**. * **Impact Notional:** **1,000 USDC** by default. `GOLD-USD` and `US100-USD` use **10,000 USDC**. * **Interest Rate:** **None**. ### 1. Premium Index The Premium Index ($P$) represents the premium or discount of the contract relative to the spot price. It is calculated using the **Impact Bid** and **Impact Ask** prices from the orderbook. $$ P = \frac{\max(0, \text{Impact Bid} - \text{Index}) - \max(0, \text{Index} - \text{Impact Ask})}{\text{Index}} $$ Where: * **Impact Bid:** The average fill price to sell the Impact Notional amount. * **Impact Ask:** The average fill price to buy the Impact Notional amount. ### 2. Funding Rate The final Funding Rate applied at the end of each 60-minute interval is based on a **Time-Weighted Average (TWAP)** of the Premium Index over that interval. This method assigns higher weight to more recent premium observations. > **Note:** In the formula below, $\bar{P}$ and $F_{\text{raw}}$ are expressed in **basis points (bps)**. $$ \bar{P} = \frac{\sum_{i=0}^{N-1} (i+1) \cdot P_i}{\sum_{i=0}^{N-1} (i+1)} $$ $$ F_{\text{final}} = \frac{\bar{P}}{100} $$ Where: * $P_i$ represents the premium samples. * The weight $(i+1)$ increases for more recent samples (where $i=N-1$ is the most recent). * $F_{\text{final}}$ is the funding rate applied for payments and published on the funding stream. *Note: Unlike other exchanges, we do not apply a fixed interest rate component. The rate is purely the market-driven premium.* ## Why Funding May Be 0 Funding can be zero for normal reasons: * The symbol is outside its `market_hours` (market closed, weekend, or holiday). ## Historical Funding Data We are actively improving historical data coverage, including funding history by product. For live values, use the websocket `funding` channel. # Margin and Liquidations Source: https://docs.qfex.com/qfex/liquidation-margin-call A Detailed Description of the Liquidation Cascade QFEX is disrupting the traditional way that futures are cleared to bring capital efficiency and leverage never seen before to traditional markets. Traditional, intermediated markets hide the risk of leverage amongst their brokers, and try to regulate away tail cases with high capital requirements, leading to poor UX. We have created innovative, fair and transparent **multi-stage de-risking procedure** that prioritizes the safety of a user's wallet balance in the event of a margin call. Users can also set their leverage level to be lower than the maximum to improve their safety. All QFEX products are **cross-margined**. ## Margin Call and Close-Out Procedure The process runs **once per second**: * All users are evaluated simultaneously and on equal terms. * Progression through the Procedure halts for any user whose equity recovers mid-process. ### Initial Steps **Condition:** `Account Equity < Maintenance Margin` #### Closing of Open Orders All open orders are immediately canceled. #### Netting of Liquidated Positions * Opposite liquidated positions are **netted internally** between accounts. * Trades are booked at current Mark Price. **Example:** > Account 1: Long 100 units of Symbol Y\ > Account 2: Short 100 units of Symbol Y\ > → Positions netted, no order book impact. ### Next Steps ##### Orderbook Liquidations **Condition:** `Maintenance Margin / 2 < Account Equity < Maintenance Margin` * Compute notional amount to liquidate. * Cap notional amount to ensure that the overall amount of liquidation quantity submitted to the orderbook does not cause the 60-second EMA of this quantity to exceed the Orderbook Liquidation Limits. * Enter limit IOC orders at `Mark Price ± Liquidation Spread`. ##### Off-Orderbook Liquidation **Condition:** `Account Equity ≤ Maintenance Margin / 2` * Positive Account Equity drained into the **Reserve Fund**. * Negative equity covered from the Reserve Fund (if sufficient). * Positions transferred to Designated Liquidity Provider (DLP) participant at Mark Price, up to the maximum quantity such that the DLP Fee can be covered by the Reserve Fund. * Reserve Fund covers DLP Fees (which are 0 if the trade was risk-decreasing for the Designated Liquidity Provider). ##### Auto-Deleveraging **Condition:** `Account Equity ≤ Maintenance Margin /2` and Off-Orderbook Liquidation incomplete. Procedure: * Rank accounts with the opposite-side position on the required symbol by `(Account Equity / Position Maintenance Margin)`. * Net off positions against the opposite side accounts, in rank order, ensuring that the liquidated account is flattened with 0 Account Equity. ## Margin Call Notifications Clients receive alerts (email + browser) when margin falls below: * **75%** of Initial Margin (warning) * **66.6%** of Initial Margin (close out notification) ## Designated Liquidity Provider (DLP) Program An opt-in program for qualified market makers to absorb liquidated positions efficiently when the orderbook cannot. Allocation is **pro-rata** to Designated Liquidity Providers by available margin capacity. * Provider positions must remain within position limits. * Providers receive a **DLP Fee** for each liquidation absorbed. * Pesignated Liquidity Provider operations follow strict risk control and monitoring standards. ## Orderbook Liquidation Limits Orderbook liquidation limits vary by symbol and market condition. They are enforced against a 60-second exponential moving average of liquidation notional. ## Reserve Fund and Stress Testing Regular stress testing of the Liquidation Protocol ensures that the system can handle extreme market conditions while maintaining adequate Reserve Fund levels. The exchange monitors liquidation frequency and effectiveness to optimize protocol parameters and ensure continued system resilience. # Market Makers Source: https://docs.qfex.com/qfex/market-makers Institutional connectivity enquiries # Market makers If you are a market maker and want to discuss institutional connectivity to QFEX, contact [mm@qfex.com](mailto:mm@qfex.com). Please include relevant details about your firm, your integration requirements, and the markets you are interested in. # Order Entry Source: https://docs.qfex.com/qfex/order-types Supported Order Types and Times in Force ## Order Types ### Market Orders * Execute immediately at the best available price. * Provide **certainty of execution** but not certainty of price. * Cannot include **Good-Till-Cancelled (GTC)** instructions. ### Limit Orders * Specify both **quantity** and **price limit** (max for buy, min for sell). * If not filled immediately, rest in the order book at the specified price. ### Add Liquidity Only (ALO) Orders * Execute **only if they add liquidity**. * If an ALO order would immediately match with an existing order, it is **cancelled** instead. Any of the above types can optionally specify a `take_profit` and `stop_loss` price. This stages *Stop Order(s)* at the exchange: ### Stop Orders * Must be either `take_profit` or `stop_loss`. * Convert to a Market Order when the Mark Price reaches the specified price. * Act only to decrease position at the time of execution; otherwise, the order could be rejected, or other stop orders cancelled. ## Time In Force ### Fill-or-Kill (FOK) * Must execute **entirely and immediately**, or be cancelled. * Suitable for **large block trades** or hedging strategies. ### Immediate-or-Cancel (IOC) * Executes any **immediately available portion**, cancelling the rest. * Reduces risk of resting orders in volatile markets. ### Good-Till-Cancelled (GTC) * Remains active until executed or manually cancelled. * Applies only to **limit** and **ALO** orders (not market orders). * Persists across sessions. ### Instruction Availability Table | Order Type | FOK | IOC | GTC | | ----------------- | --- | --- | --- | | **Market Orders** | ❌ | ✅ | ❌ | | **Limit Orders** | ✅ | ✅ | ✅ | | **ALO Orders** | ❌ | ❌ | ✅ | | **Stop Orders** | ❌ | ✅ | ❌ | # Blocked Countries and Restrictions Source: https://docs.qfex.com/qfex/prohibited-jurisdictions Location plays a major role determining which customers a platform is allowed to serve. For details on the countries and regions where QFEX cannot onboard users, see the list of [restricted locations](./faq#what-are-the-restricted-locations). # QFEX Referral Program Source: https://docs.qfex.com/qfex/referral Earn Cash Rewards ## Overview We’re excited to introduce QFEX’s Invite & Referral Program, designed to reward active traders for helping grow our trading community. Earn passive income every time your referrals trade on QFEX—the more they trade! QFEX is currently **invite-only**. Every new user must join using a valid invitation code from an existing QFEX user. To earn your first invitation codes, trade **\$100,000** in cumulative perpetual futures notional volume over the last **14 days**. Once you qualify, you'll receive **5 invitation codes**. Each invitation code is **one-time use** and **valid for 14 days**. After your first unlock, you'll receive **5 additional invitation codes** every time the combined 14-day trading volume of **you and your direct referrals** reaches **\$5,000,000**. Users who sign up using your invitation code also receive a **10% discount on trading fees**. QFEX's 3-tier Referral System rewards you across multiple levels. Your referral tier is determined by the combined rolling 14-day trading volume generated by you and your direct referrals. | Partner Tier | Qualification | Level 1 | Level 2 | Level 3 | | ------------ | ----------------------------- | :-----: | :-----: | :-----: | | **Tier 1** | Default | **10%** | **2%** | **1%** | | **Tier 2** | ≥ \$15M rolling 14-day volume | **20%** | **4%** | **2%** | | **Tier 3** | ≥ \$25M rolling 14-day volume | **30%** | **6%** | **3%** | ## Detailed Breakdown ### Level 1: Direct Referrals Users who sign up using your invitation code. Depending on your current referral tier, you earn **10% / 20% / 30%** of QFEX's net fee on every trade made by your Level 1 referrals. Example: You refer Person B, who trades \$100,000 in a day. * QFEX's Fee on Person B: \$100,000 × 0.1% = \$100 * Tier 1 Commission: \$10 * Tier 2 Commission: \$20 * Tier 3 Commission: \$30 ### Level 2: Indirect Referrals Users who sign up using the invitation codes of your Level 1 referrals. Depending on your current referral tier, you earn **2% / 4% / 6%** of QFEX's net fee on every trade made by your Level 2 referrals. Example: Person B refers Person C, who trades \$100,000 in a day. * QFEX's Fee on Person C: \$100,000 × 0.1% = \$100 * Tier 1 Commission: \$2 * Tier 2 Commission: \$4 * Tier 3 Commission: \$6 ### Level 3: Extended Referrals Users who sign up using the invitation codes of your Level 2 referrals. Depending on your current referral tier, you earn **1% / 2% / 3%** of QFEX's net fee on every trade made by your Level 3 referrals. Example: Person C refers Person D, who trades \$100,000 in a day. * QFEX's Fee on Person D: \$100,000 × 0.1% = \$100 * Tier 1 Commission: \$1 * Tier 2 Commission: \$2 * Tier 3 Commission: \$3 ## Important Notes * QFEX is currently invite-only. A valid invitation code is required to create a new account. * Invitation codes are earned by active traders based on trading volume. * Each invitation code is one-time use and expires 14 days after issuance. * Users referred through your invitation code receive a 10% discount on trading fees. * Your referral tier is determined by the combined rolling 14-day trading volume generated by you and your direct referrals. * Commissions are based on QFEX’s net fee, adjusted for user discounts and promotions, so your share reflects the actual net fee collected. * Referral rewards are uncapped. * You must have completed onboarding to be eligible for referral scheme payouts. * QFEX may modify, suspend, or terminate the Invite & Referral Program at any time. # Risk Limits Source: https://docs.qfex.com/qfex/risk-limits Stay Safe We allow trading including overnight and on weekends, when some underlier markets are closed or less liquid. For now, this may lead to lower liquidity conditions that could make the exchange less safe for users. To ensure safety, we impose some limits on positions, prices and open interest in the early days of the exchange. ## Definitions Market Close refers to periods when major reference markets (e.g., NYSE, CME) are closed. | Asset Class | Weekday Overnight Hours | Weekend Hours | | --------------------- | -------------------------- | ------------------------------ | | **Single Stocks** | NYSE closed (Mon–Fri ET)\* | Fri afternoon → Mon morning ET | | **US Equity Indices** | CME closed (Sun–Fri ET)\* | Fri afternoon → Sun evening ET | | **Commodities** | CME closed (Sun–Fri ET)\* | Fri afternoon → Sun evening ET | | **FX** | N/A (open 24/5) | Fri 22:00 → Sun 22:00 UTC | > *U.S. bank holidays are treated as normal business days for Market-Close logic.* ## Leverage Limits | Markets | Maximum Leverage | | --------------------------------------------------- | ---------------- | | **Active Korean equities** | 7:1 | | **Other active equities, `CL-USD`, and `DRAM-USD`** | 10:1 | | **Commodities other than `CL-USD`** | 20:1 | | **Indices and funds other than `DRAM-USD`** | 30:1 | > Example: 30× leverage requires approximately **3.33% Initial Margin**. See the [Specification Index](/qfex/specification-index) for per-symbol leverage and execution parameters. ## Position Limits | Markets | Maximum Position (USD Notional) | | ---------------------------------------------------- | ------------------------------- | | **Active equities** | \$5,000,000 | | **Active commodities** | \$5,000,000 | | **Active indices and funds** | \$10,000,000 | | **`BMNR-USD`, `GLXY-USD`, and `GOLD-USD` overrides** | \$10,000,000 | These are limits for the default margin group. Participant-specific margin groups and other risk controls may impose different limits. During Market Close: * Position size per participant is limited to the **Max Position Percentage** of normal size. * Participants exceeding this limit can only **reduce exposure**: * For long positions: only sell orders accepted. * For short positions: only buy orders accepted. | Trading Period | Max Position % of Normal Limit | | -------------- | ------------------------------ | | **Overnight** | 50% | | **Weekend** | 10% | ## Price Bands We implement price bands to protect users against: * their own fat finger errors; * manipulative practices from other market participants. For all products, buy orders at a price greater than the upper band, and sell orders at a price less than the lower band, are rejected by the system before reaching the matching engine. The bands are set by taking a fixed percentage above and below the last known Market Data Price of the product, set every minute. The percentages are as follows: * US equities: 10% * US indices: 5% * Commodities: 5% * FX: 2% Price bands may be relaxed at the sole discretion of QFEX for the following reasons: * Exceptional market volatility * Stock splits or reverse stock split of equities ## Open Interest Limits Once a product exceeds **\$10m** of open interest, a participant's potential open interest is limited to **10%** of total open interest in that market. There is currently no absolute market-wide open-interest cap configured. See the [Specification Index](/qfex/specification-index) for the consolidated policy. # Roll Schedules Source: https://docs.qfex.com/qfex/roll-schedules Published dated-futures contracts and roll boundaries used by QFEX oracle pricing. Some QFEX perpetual futures derive their oracle price from a dated futures contract. This page lists all 35 calendar entries returned by the production settlement-calendar API from **2026-01-01 00:00 UTC** onward. The latest published roll boundary in this data is **2027-02-11 22:30 UTC**. Times are UTC. `active_until` is the boundary through which the listed dated future remains active for the QFEX symbol. Query the API at execution time instead of hardcoding this page because the published calendar can change. ## Published calendar ### CL-USD | Dated future | Active until (UTC) | Futures expiration (UTC) | | ------------ | -------------------- | ------------------------ | | `CLJ6` | 2026-03-12 21:30 UTC | 2026-03-20 21:30 UTC | | `CLK6` | 2026-04-14 21:30 UTC | 2026-04-21 21:30 UTC | | `CLM6` | 2026-05-13 21:30 UTC | 2026-05-18 21:30 UTC | | `CLN6` | 2026-06-11 21:30 UTC | 2026-06-10 21:30 UTC | | `CLQ6` | 2026-07-14 21:30 UTC | 2026-07-11 21:30 UTC | | `CLU6` | 2026-08-14 21:30 UTC | 2026-08-20 21:30 UTC | | `CLV6` | 2026-09-14 21:30 UTC | 2026-09-22 21:30 UTC | | `CLX6` | 2026-10-14 21:30 UTC | 2026-10-20 21:30 UTC | | `CLZ6` | 2026-11-13 22:30 UTC | 2026-11-20 22:30 UTC | | `CLF7` | 2026-12-14 22:30 UTC | 2026-12-21 22:30 UTC | | `CLG7` | 2027-01-14 22:30 UTC | 2027-01-20 22:30 UTC | ### COPPER-USD | Dated future | Active until (UTC) | Futures expiration (UTC) | | ------------ | -------------------- | ------------------------ | | `HGK6` | 2026-04-14 21:30 UTC | 2026-04-21 21:30 UTC | | `HGN6` | 2026-06-11 21:30 UTC | 2026-06-16 21:30 UTC | | `HGU6` | 2026-08-13 21:30 UTC | 2026-09-28 21:30 UTC | | `HGZ6` | 2026-11-12 22:30 UTC | 2026-12-29 22:30 UTC | | `HGH7` | 2027-02-11 22:30 UTC | 2027-03-29 21:30 UTC | ### NATGAS-USD | Dated future | Active until (UTC) | Futures expiration (UTC) | | ------------ | -------------------- | ------------------------ | | `NGJ26` | 2026-03-12 21:30 UTC | 2026-03-27 21:30 UTC | | `NGK26` | 2026-04-14 21:30 UTC | 2026-04-28 21:30 UTC | | `NGM26` | 2026-05-13 21:30 UTC | 2026-05-27 21:30 UTC | | `NGN26` | 2026-06-11 21:30 UTC | 2026-06-10 21:30 UTC | | `NGQ26` | 2026-07-14 21:30 UTC | 2026-07-20 21:30 UTC | | `NGU26` | 2026-08-14 21:30 UTC | 2026-08-27 21:30 UTC | | `NGV26` | 2026-09-14 21:30 UTC | 2026-09-28 21:30 UTC | | `NGX26` | 2026-10-14 21:30 UTC | 2026-10-28 21:30 UTC | | `NGZ26` | 2026-11-13 22:30 UTC | 2026-11-25 22:30 UTC | | `NGF27` | 2026-12-14 22:30 UTC | 2026-12-29 22:30 UTC | | `NGG27` | 2027-01-14 22:30 UTC | 2027-01-27 22:30 UTC | ### US100-USD | Dated future | Active until (UTC) | Futures expiration (UTC) | | ------------ | -------------------- | ------------------------ | | `NQH6` | 2026-03-13 21:30 UTC | 2026-03-18 13:30 UTC | | `NQM6` | 2026-06-14 21:30 UTC | 2026-06-19 13:30 UTC | | `NQU6` | 2026-09-13 21:30 UTC | 2026-09-18 13:30 UTC | | `NQZ6` | 2026-12-13 21:30 UTC | 2026-12-18 13:30 UTC | ### US500-USD | Dated future | Active until (UTC) | Futures expiration (UTC) | | ------------ | -------------------- | ------------------------ | | `ESH6` | 2026-03-13 21:30 UTC | 2026-03-18 13:30 UTC | | `ESM6` | 2026-06-14 21:30 UTC | 2026-06-19 13:30 UTC | | `ESU6` | 2026-09-13 21:30 UTC | 2026-09-18 13:30 UTC | | `ESZ6` | 2026-12-13 21:30 UTC | 2026-12-18 13:30 UTC | ## Roll behavior `US100-USD` and `US500-USD` switch to the next listed contract after the prior contract's `active_until` boundary. For `CL-USD`, `COPPER-USD`, and `NATGAS-USD`, the oracle blends the front and next contracts over the final five CME business-day boundaries before `active_until`. Weekends and configured CME holidays do not advance the blend. Each business-day boundary lands at **17:30 America/New\_York**, the same wall-clock time as `active_until`. In the published calendar above that time appears as **21:30 UTC** while US Eastern is on daylight time and **22:30 UTC** while it is on standard time. The blend advances by exactly one row of the table below at each of these daily boundaries, so the changeover to 100% next contract completes at the `active_until` timestamp itself. | CME business days remaining until `active_until` | Front contract | Next contract | | -----------------------------------------------: | -------------: | ------------: | | 5 or more | 100% | 0% | | 4 | 80% | 20% | | 3 | 60% | 40% | | 2 | 40% | 60% | | 1 | 20% | 80% | | 0 | 0% | 100% | The first step off 100% front therefore occurs at the 17:30 ET boundary five CME business days before `active_until`, and each subsequent business day shifts another 20% until the next contract is fully active. ## Query the live calendar With the [QFEX CLI](/api-reference/cli): ```sh theme={null} qfex market settlement-calendar --symbol CL-USD qfex market settlement-calendar --symbol CL-USD --time 2026-09-01T00:00:00Z ``` Or call the production REST endpoint directly: ```sh theme={null} curl --get 'https://api.qfex.com/settlement-calendar' \ --data-urlencode 'symbol=CL-USD' \ --data-urlencode 'time=2026-09-01T00:00:00Z' ``` The response contains `qfex_symbol`, `future_symbol`, `active_until`, and `expiration`. If `time` is omitted, the endpoint uses the current UTC time. # Specification Index Source: https://docs.qfex.com/qfex/specification-index A consolidated view of active QFEX production contract, execution, session, and risk parameters. This index contains the 141 markets marked active in the production refdata configuration. Quantities are expressed in units of the underlying asset and notionals are expressed in USD unless stated otherwise. All listed products are perpetual futures, cross-margined in USDC, and available for trading 24/7. The reference-price hours below are the periods when QFEX actively consumes underlier prices and [funding](/qfex/funding) can accrue. Funding is `0` outside these hours. ## Active markets ### Commodities | Instrument | Underlying | Max leverage | Default position limit | Tick / lot | Quantity range | Reference-price hours | | ------------- | ------------- | -----------: | ---------------------: | -----------: | ---------------: | ----------------------------------------------- | | `CL-USD` | CL / USD | 20× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 17:00–Fri 16:00 CT; daily 16:00–17:00 pause | | `COPPER-USD` | COPPER / USD | 20× | \$5m | 0.001 / 0.1 | 1–100,000,000 | Sun 17:00–Fri 20:00 ET | | `GOLD-USD` | GOLD / USD | 30× | \$10m | 0.1 / 0.0001 | 0.001–10,000,000 | Sun 17:00–Fri 17:00 ET | | `NATGAS-USD` | NATGAS / USD | 20× | \$5m | 0.001 / 0.01 | 1–100,000,000 | Sun 17:00–Fri 20:00 ET | | `SILVER-USD` | SILVER / USD | 20× | \$5m | 0.01 / 0.001 | 0.001–10,000,000 | Sun 17:00–Fri 17:00 ET | | `URANIUM-USD` | URANIUM / USD | 20× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | ### Indices and funds | Instrument | Underlying | Max leverage | Default position limit | Tick / lot | Quantity range | Reference-price hours | | ------------ | ------------ | -----------: | ---------------------: | -----------: | ---------------: | ----------------------------------------------- | | `DRAM-USD` | DRAM / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `HSI-USD` | HSI / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `IGV-USD` | IGV / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `KOSPI-USD` | KOSPI / USD | 30× | \$10m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `NIKKEI-USD` | NIKKEI / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `SOXL-USD` | SOXL / USD | 30× | \$10m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 17:00–Fri 20:00 ET | | `TAIEX-USD` | TAIEX / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `US100-USD` | US100 / USD | 30× | \$10m | 1 / 0.0001 | 0.001–10,000,000 | Sun 17:00–Fri 16:00 CT; daily 16:00–17:00 pause | | `US500-USD` | US500 / USD | 30× | \$10m | 0.1 / 0.001 | 0.001–10,000,000 | Sun 17:00–Fri 16:00 CT; daily 16:00–17:00 pause | | `XLE-USD` | XLE / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | | `XLF-USD` | XLF / USD | 30× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 17:00–Fri 20:00 ET | ### Equities | Instrument | Underlying | Max leverage | Default position limit | Tick / lot | Quantity range | Reference-price hours | | ------------- | ------------- | -----------: | ---------------------: | -------------: | -----------------: | ------------------------------------- | | `AAOI-USD` | AAOI / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `AAPL-USD` | AAPL / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ABCL-USD` | ABCL / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ABSI-USD` | ABSI / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ADEA-USD` | ADEA / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `AEHR-USD` | AEHR / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ALAB-USD` | ALAB / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ALNT-USD` | ALNT / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `AMD-USD` | AMD / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `AMZN-USD` | AMZN / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ARM-USD` | ARM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ASTS-USD` | ASTS / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `AVGO-USD` | AVGO / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `AXTI-USD` | AXTI / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BA-USD` | BA / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BABA-USD` | BABA / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BB-USD` | BB / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BE-USD` | BE / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BFLY-USD` | BFLY / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BMNP-USD` | BMNP / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BMNR-USD` | BMNR / USD | 10× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BOT-USD` | BOT / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BRK.B-USD` | BRK.B / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `BX-USD` | BX / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CAT-USD` | CAT / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CBRS-USD` | CBRS / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CCXI-USD` | CCXI / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CGNX-USD` | CGNX / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CHYM-USD` | CHYM / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CIEN-USD` | CIEN / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CIFR-USD` | CIFR / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `COHR-USD` | COHR / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `COIN-USD` | COIN / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `COST-USD` | COST / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CRCL-USD` | CRCL / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CRDO-USD` | CRDO / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CRM-USD` | CRM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CRWD-USD` | CRWD / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CRWV-USD` | CRWV / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `CVNA-USD` | CVNA / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `DGXX-USD` | DGXX / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `DXYZ-USD` | DXYZ / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `FCEL-USD` | FCEL / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `FLEX-USD` | FLEX / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `GD-USD` | GD / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `GLW-USD` | GLW / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `GLXY-USD` | GLXY / USD | 10× | \$10m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `GOOGL-USD` | GOOGL / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `GS-USD` | GS / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `HIMS-USD` | HIMS / USD | 10× | \$5m | 0.01 / 0.01 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `HOOD-USD` | HOOD / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `HUT-USD` | HUT / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `HYUNDAI-KRW` | HYUNDAI / KRW | 10× | \$5m | 100 / 0.000001 | 0.00001–10,000,000 | Weekdays 09:00–15:30 KST | | `IBM-USD` | IBM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ILMN-USD` | ILMN / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `INTC-USD` | INTC / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `IONQ-USD` | IONQ / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `IOVA-USD` | IOVA / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `IREN-USD` | IREN / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `JBL-USD` | JBL / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `JPM-USD` | JPM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `KEEL-USD` | KEEL / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `LITE-USD` | LITE / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `LLY-USD` | LLY / USD | 10× | \$5m | 0.01 / 0.0001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `LMT-USD` | LMT / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `LPTH-USD` | LPTH / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `LRCX-USD` | LRCX / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `LSCC-USD` | LSCC / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `META-USD` | META / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `MITK-USD` | MITK / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `MRVL-USD` | MRVL / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `MSFT-USD` | MSFT / USD | 10× | \$5m | 0.01 / 0.001 | 0.02–10,000,000 | Sun 20:00–Fri 20:00 ET | | `MSTR-USD` | MSTR / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `MU-USD` | MU / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `MX-USD` | MX / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `NBIS-USD` | NBIS / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `NBR-USD` | NBR / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `NOC-USD` | NOC / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `NUAI-USD` | NUAI / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `NVDA-USD` | NVDA / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `NVTS-USD` | NVTS / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ORCL-USD` | ORCL / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `OUST-USD` | OUST / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `PANW-USD` | PANW / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `PENG-USD` | PENG / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `PL-USD` | PL / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `PLTR-USD` | PLTR / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `PLUG-USD` | PLUG / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `QCOM-USD` | QCOM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `QURE-USD` | QURE / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `RCAT-USD` | RCAT / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `RDCM-USD` | RDCM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `RDDT-USD` | RDDT / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `RDW-USD` | RDW / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `RKLB-USD` | RKLB / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `RTX-USD` | RTX / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SAMSUNG-KRW` | SAMSUNG / KRW | 10× | \$5m | 10 / 0.00001 | 0.0001–10,000,000 | Weekdays 09:00–15:30 KST | | `SBET-USD` | SBET / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SERV-USD` | SERV / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SHAZ-USD` | SHAZ / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SIVE-SEK` | SIVE / SEK | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Weekdays 09:00–17:00 Europe/Stockholm | | `SKHY-USD` | SKHY / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–100,000 | Sun 20:00–Fri 20:00 ET | | `SKHYNIX-KRW` | SKHYNIX / KRW | 10× | \$5m | 100 / 0.000001 | 0.00001–10,000,000 | Weekdays 09:00–15:30 KST | | `SKM-USD` | SKM / USD | 10× | \$5m | 0.01 / 0.01 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SMCI-USD` | SMCI / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SNDK-USD` | SNDK / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SPCE-USD` | SPCE / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SPCX-USD` | SPCX / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `STRC-USD` | STRC / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `SUIG-USD` | SUIG / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `TE-USD` | TE / USD | 10× | \$5m | 0.01 / 0.1 | 1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `TMO-USD` | TMO / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `TSLA-USD` | TSLA / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `TTWO-USD` | TTWO / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `UBER-USD` | UBER / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `VCX-USD` | VCX / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `WDC-USD` | WDC / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `WMT-USD` | WMT / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `WOLF-USD` | WOLF / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `WULF-USD` | WULF / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `WYFI-USD` | WYFI / USD | 10× | \$5m | 0.01 / 0.01 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `XOM-USD` | XOM / USD | 10× | \$5m | 0.01 / 0.001 | 0.1–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ZBRA-USD` | ZBRA / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | | `ZM-USD` | ZM / USD | 10× | \$5m | 0.01 / 0.001 | 0.01–10,000,000 | Sun 20:00–Fri 20:00 ET | ## How to read the index * **Max leverage** is the highest leverage tier available to the default margin group. Participant-specific groups may differ. * **Default position limit** is the maximum notional available in the default margin group. Participant-specific margin groups and other risk controls may impose a different limit. * **Tick / lot** shows the minimum price increment followed by the minimum quantity increment, both in the instrument's quoted units. * **Quantity range** shows the minimum and maximum order quantity. * **Reference-price hours** follow the named local timezone and may change on market holidays. All active markets support Limit, Market, and Add Liquidity Only (ALO) orders. Supported time-in-force instructions are Good-Till-Cancelled (GTC), Immediate-or-Cancel (IOC), and Fill-or-Kill (FOK), subject to the [order type compatibility rules](/qfex/order-types). ## Open-interest controls Each active production market uses the following open-interest policy: * The participant concentration check activates when total open interest exceeds **\$10m**. * Above that threshold, a participant's potential open interest is limited to **10% of total market open interest**. * No absolute market-wide open-interest cap is configured. ## Machine-readable specifications Use reference data for the latest machine-readable market status, increments, limits, and session schedule: ```sh theme={null} qfex market refdata ``` Reference data is also available from [`GET /refdata`](https://api.qfex.com/refdata) and the [Reference Data websocket channel](/websocket/channels/mds/refdata). # Stablecoins Source: https://docs.qfex.com/qfex/stablecoins Pay via Stablecoins QFEX supports funding via [USDC](https://circle.com) on Arbitrum. Client funds are held by BitGo Bank & Trust, National Association, a national banking association chartered under the laws of the United States and authorized by the Office of the Comptroller of the Currency to exercise fiduciary and custodial powers. ## How To Deposit USDC 1. Open **Deposit / Withdraw** from your account header. 2. Select **Deposit funds**. 3. Choose **USDC** from the available deposit currencies. 4. Send USDC on **Arbitrum One** to the deposit address shown in the app. Only deposit USDC via the Arbitrum One network. Deposits sent using a different asset or network may be lost. # Subaccounts Source: https://docs.qfex.com/qfex/subaccounts Separate your margin and risk QFEX supports subaccounts as a means to separate margin and risk without creating multiple accounts. All subaccounts share a common email and login, but act as separate accounts when it comes to order entry and margin. Deposits all go into the main account, and cash balances can be transferred between the main account and subaccounts using the [UI](https://qfex.com/trade), [REST API](../api-reference/subaccounts-api) or [CLI](../api-reference/cli). # Changelog Source: https://docs.qfex.com/websocket/changelog Product updates and announcements Added default\_max\_leverage field to refdata response. See [here](/websocket/channels/mds/refdata) for further details Added funding scaling documentation. The final funding rate is now documented as scaled by `1/100`, and the funding stream reflects the post-scaling value. See [here](/websocket/channels/mds/funding_rate), [here](/qfex/contract-specifications), and [here](/qfex/faq) for further details Added the `fills` channel and fill response payload documentation. See [here](/websocket/channels/trade/fills) for further details Updated trades response to include `execution_type`. See [here](/websocket/channels/mds/trades) for further details Updated order response to include trade\_id. This is used for order responses with a status of FILLED, it provides the unique trade id of that fill. See [here](/websocket/channels/trade/order) for further details Updated get\_user\_trades endpoint to support more filtering. See [here](/websocket/channels/trade/get_user_trades) for further details Updated stop order response type. Type is now `STOP_LOSS` and `TAKE_PROFIT`. Stop orders are shown in the `orders` key in `get_orders_response` See [here](/websocket/channels/trade/get_user_orders) and [here](/api-reference/enums) for further details Added documentation for stop orders. See [here](/websocket/channels/trade/stop_add_order), [here](/websocket/channels/trade/stop_modify_order) and [here](/websocket/channels/trade/stop_cancel_order) for further details Added Close Position request. See [here](/websocket/channels/trade/close_position) for further details This is only intended for use in the frontend as a quick way to close a position. Added HMAC-SHA256 authentication requirements for the trade WebSocket, including refreshed client samples. See [here](/websocket/channels/trade/authenticate) for further details Documented the new cancel-on-disconnect channel with end-to-end examples for Python, Node.js, Go, and Java. See [here](/websocket/channels/trade/cancel_on_disconnect) for further details You must now include order type in a modify order See [here](/websocket/channels/trade/modify_order) for further details. You must now subscribe to order responses. See [here](/websocket/channels/trade/order) for further details. # Pulsed BBO Source: https://docs.qfex.com/websocket/channels/mds/bbo QFEX provides a **pulsed best bid/offer (BBO) stream** for all symbols via websocket. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["bbo"], "symbols": ["AAPL-USD", "US500-USD"] } ``` Or subscribe to all symbols with a wildcard: ```json theme={null} { "type": "subscribe", "channels": ["bbo"], "symbols": ["*"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["bbo"], "symbols": ["US500-USD"] # or ["*"] } ws.send(json.dumps(sub)) def on_message(ws, message): data = json.loads(message) print("BBO update:", json.dumps(data, indent=2)) def on_error(ws, error): print("Error:", error) def on_close(ws, close_status_code, close_msg): print("Closed:", close_status_code, close_msg) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close, ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["bbo"], symbols: ["US500-USD"], // or ["*"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { try { const data = JSON.parse(msg.toString()); console.log("BBO update:", data); } catch (e) { console.error("Parse error:", e); } }); ws.on("error", (err) => console.error("WS error:", err)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()), ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "fmt" "log" "os" "os/signal" "github.com/gorilla/websocket" ) func main() { c, _, err := websocket.DefaultDialer.Dial("wss://mds.qfex.com", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() sub := map[string]interface{}{ "type": "subscribe", "channels": []string{"bbo"}, "symbols": []string{"US500-USD"}, // or []string{"*"} } if err := c.WriteJSON(sub); err != nil { log.Fatal("write:", err) } done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("BBO update: %s\n", message) } }() // keep running until Ctrl+C interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) <-interrupt } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class BboWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("wss://mds.qfex.com") .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { String sub = "{\"type\":\"subscribe\",\"channels\":[\"bbo\"],\"symbols\":[\"US500-USD\"]}"; webSocket.send(sub); } @Override public void onMessage(WebSocket webSocket, String text) { System.out.println("BBO update: " + text); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(request, listener); // Keep JVM alive try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "type": "bbo", "symbol": "AAPL-USD", "bid": [["10101.10", "0.45054140"]], "ask": [["10102.55", "0.57753524"]], "sequence": 30272539, "time": "2025-09-04T09:26:39.545268322Z" } ``` ### Unsubscribe (optional) ```json theme={null} { "type": "unsubscribe", "channels": ["bbo"], "symbols": ["US500-USD"] } ``` *** **Notes** * Similar to Level 2 but only contains **top-of-book** (best bid/ask). * Updates are **pulsed**. * Supports wildcard `*` to receive BBO for all symbols. # Funding Rate Source: https://docs.qfex.com/websocket/channels/mds/funding_rate QFEX provides a **stream of the current funding rate** for any symbol, representing the rate if the funding window were to end *right now*.\ At the end of each funding window, the final rate is used to compute **funding payments**. The streamed value is the post-scaling final rate: $F_{\text{final}} = F_{\text{raw}} / 100$. Funding is only active during each symbol's configured market hours. Outside those hours, funding rate is `0`. See [`/qfex/funding`](/qfex/funding). ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["funding"], "symbols": ["AAPL-USD", "US500-USD"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["funding"], "symbols": ["US500-USD"] # or ["*"] } ws.send(json.dumps(sub)) def on_message(ws, message): data = json.loads(message) print("Funding update:", json.dumps(data, indent=2)) def on_error(ws, error): print("Error:", error) def on_close(ws, close_status_code, close_msg): print("Closed:", close_status_code, close_msg) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close, ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["funding"], symbols: ["US500-USD"], // or ["*"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { try { const data = JSON.parse(msg.toString()); console.log("Funding update:", data); } catch (e) { console.error("Parse error:", e); } }); ws.on("error", (err) => console.error("WS error:", err)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "fmt" "log" "os" "os/signal" "github.com/gorilla/websocket" ) func main() { c, _, err := websocket.DefaultDialer.Dial("wss://mds.qfex.com", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() sub := map[string]interface{}{ "type": "subscribe", "channels": []string{"funding"}, "symbols": []string{"US500-USD"}, // or []string{"*"} } if err := c.WriteJSON(sub); err != nil { log.Fatal("write:", err) } done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("Funding update: %s\n", message) } }() // keep running until Ctrl+C interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) <-interrupt } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class FundingWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("wss://mds.qfex.com") .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { String sub = "{\"type\":\"subscribe\",\"channels\":[\"funding\"],\"symbols\":[\"US500-USD\"]}"; webSocket.send(sub); } @Override public void onMessage(WebSocket webSocket, String text) { System.out.println("Funding update: " + text); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(request, listener); // Keep JVM alive try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "type": "funding", "sequence": 50, "time": "2014-11-07T08:19:27.028459Z", "symbol": "AAPL-USD", "time_remaining": 30, "funding_rate": "0.021" } ``` ### Unsubscribe (optional) ```json theme={null} { "type": "unsubscribe", "channels": ["funding"], "symbols": ["US500-USD"] } ``` *** **Notes** * Represents the **current implied funding rate** if the window ended immediately. * Pulsed during funding calculation window. * Outside symbol market hours, funding rate = `0`. # Mark Price Source: https://docs.qfex.com/websocket/channels/mds/mark_price Subscribe to real-time mark price updates for symbols. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["mark_price"], "symbols": ["AAPL-USD"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["mark_price"], "symbols": ["AAPL-USD"] } ws.send(json.dumps(sub)) def on_message(ws, message): print("Update:", message) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["mark_price"], symbols: ["AAPL-USD"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { console.log("Update:", msg.toString()); }); ``` ## Example Response ```json theme={null} { "type": "mark_price", "symbol": "AAPL-USD", "price": "437.45", "time": "2025-05-08T20:52:48.000Z" } ``` # Market Stats Source: https://docs.qfex.com/websocket/channels/mds/market_stats Subscribe to consolidated market statistics for one symbol or all symbols. The `market_stats` stream combines the latest BBO, mark price, open interest, and current daily volume into one message. On subscribe, it sends the latest snapshot when data is available, then pushes refreshed stats once per second. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["market_stats"], "symbols": ["AAPL-USD"] } ``` Or subscribe to all symbols with a wildcard: ```json theme={null} { "type": "subscribe", "channels": ["market_stats"], "symbols": ["*"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["market_stats"], "symbols": ["*"] } ws.send(json.dumps(sub)) def on_message(ws, message): print("Market stats:", message) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["market_stats"], symbols: ["*"], }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { console.log("Market stats:", msg.toString()); }); ``` ## Example Response ```json theme={null} { "type": "market_stats", "sequence": 30272540, "time": "2025-09-04T09:26:40Z", "symbol": "*", "bbos": [ { "time": "2025-09-04T09:26:39.545268322Z", "symbol": "AAPL-USD", "bid": [["10101.1", "0.4505414"]], "ask": [["10102.55", "0.57753524"]] } ], "mark_prices": [ { "time": "2025-09-04T09:26:39.545268322Z", "symbol": "AAPL-USD", "price": "10102" } ], "open_interests": [ { "time": "2025-09-04T09:26:39.545268322Z", "symbol": "AAPL-USD", "open_interest": "12.5" } ], "daily_volumes": [ { "symbol": "AAPL-USD", "volume": "12.5" } ] } ``` ### Unsubscribe (optional) ```json theme={null} { "type": "unsubscribe", "channels": ["market_stats"], "symbols": ["*"] } ``` *** **Notes** * `symbols` supports a single symbol, multiple symbols, or wildcard `*`. * `bbos`, `mark_prices`, `open_interests`, and `daily_volumes` are arrays. Arrays can be empty when no latest value is available for that component. * Daily volume is counted from the daily reset at **20:00 America/Chicago**. * `market_stats` ignores `intervals` and `sig_figs`; it always uses the default subscription filter. # Minmax Price Source: https://docs.qfex.com/websocket/channels/mds/minmax_price Subscribe to real-time minimum and maximum price updates for symbols. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["minmax_price"], "symbols": ["AAPL-USD"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["minmax_price"], "symbols": ["AAPL-USD"] } ws.send(json.dumps(sub)) def on_message(ws, message): print("Update:", message) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["minmax_price"], symbols: ["AAPL-USD"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { console.log("Update:", msg.toString()); }); ``` ## Example Response ```json theme={null} { "type": "minmax_price", "symbol": "AAPL-USD", "min_price": "400.00", "max_price": "450.00", "time": "2025-05-08T20:52:48.000Z" } ``` # Open Interest Source: https://docs.qfex.com/websocket/channels/mds/open_interest Subscribe to real-time open interest updates for symbols. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["open_interest"], "symbols": ["AAPL-USD"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["open_interest"], "symbols": ["AAPL-USD"] } ws.send(json.dumps(sub)) def on_message(ws, message): print("Update:", message) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["open_interest"], symbols: ["AAPL-USD"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { console.log("Update:", msg.toString()); }); ``` ## Example Response ```json theme={null} { "type": "open_interest", "symbol": "AAPL-USD", "open_interest": "1000000", "time": "2025-05-08T20:52:48.000Z" } ``` # Pulsed Order Book Source: https://docs.qfex.com/websocket/channels/mds/orderbook QFEX provides a **500ms pulsed stream** of the order book up to 20 levels deep via websocket. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["level2"], "symbols": ["AAPL-USD", "US500-USD"] } ``` You can also use a wildcard to subscribe to **all** symbols: ```json theme={null} { "type": "subscribe", "channels": ["level2"], "symbols": ["*"] } ``` ### Significant Figures (Optional) You can optionally specify `sig_figs` to aggregate order book levels: ```json theme={null} { "type": "subscribe", "channels": ["level2"], "symbols": ["AAPL-USD"], "sig_figs": [1] } ``` * **Default**: `0` (no aggregation) * **Valid values**: `0`, `1`, or `2` * **Purpose**: Aggregates individual levels to the next significant figure from the tick size * Bids round down * Offers round up * **Response format**: Unchanged (same structure as without `sig_figs`) ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["level2"], "symbols": ["US500-USD"] # or ["*"] } ws.send(json.dumps(sub)) def on_message(ws, message): data = json.loads(message) print("OrderBook update:", json.dumps(data, indent=2)) def on_error(ws, error): print("Error:", error) def on_close(ws, close_status_code, close_msg): print("Closed:", close_status_code, close_msg) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close, ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["level2"], symbols: ["US500-USD"], // or ["*"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { try { const data = JSON.parse(msg.toString()); console.log("OrderBook update:", data); } catch (e) { console.error("Parse error:", e); } }); ws.on("error", (err) => console.error("WS error:", err)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "fmt" "log" "os" "os/signal" "github.com/gorilla/websocket" ) func main() { c, _, err := websocket.DefaultDialer.Dial("wss://mds.qfex.com", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() sub := map[string]interface{}{ "type": "subscribe", "channels": []string{"level2"}, "symbols": []string{"US500-USD"}, // or []string{"*"} } if err := c.WriteJSON(sub); err != nil { log.Fatal("write:", err) } done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("OrderBook update: %s\n", message) } }() // keep running until Ctrl+C interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) <-interrupt } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class OrderBookWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("wss://mds.qfex.com") .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { String sub = "{\"type\":\"subscribe\",\"channels\":[\"level2\"],\"symbols\":[\"US500-USD\"]}"; webSocket.send(sub); } @Override public void onMessage(WebSocket webSocket, String text) { System.out.println("OrderBook update: " + text); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(request, listener); // Keep JVM alive try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "type": "level2", "symbol": "AAPL-USD", "bid": [ ["10101.10", "0.45054140"], ["10101.00", "0.55054140"] ], "ask": [ ["10102.55", "0.57753524"], ["10102.65", "0.57753524"] ], "sequence": 30272539, "time": "2025-09-04T09:26:39.545268322Z" } ``` ### Unsubscribe (optional) ```json theme={null} { "type": "unsubscribe", "channels": ["level2"], "symbols": ["US500-USD"] } ``` *** **Notes** * Pulsed at 50ms intervals. * Depth: up to 20 levels. * `symbols` accepts a wildcard `*` to stream all symbols. # Reference Data Source: https://docs.qfex.com/websocket/channels/mds/refdata Reference Data returns a list of all available symbols and their reference data. This is available via REST at `https://api.qfex.com/refdata`. For funding behavior by symbol, use `market_hours`. See [`/qfex/funding`](/qfex/funding). ## Example Response Shape > The websocket payloads mirror the REST fields. A single message may include one or more symbols. ```json theme={null} { "type": "refdata", "data": [ { "clobPairId": "4", "symbol": "GOOG-USD", "underlier_price": "154.16", "price_change_24h": "-2.1", "tick_size": "0.05", "lot_size": "0.001", "min_price": "112", "max_price": "209", "min_quantity": "0.001", "max_quantity": "100000000", "base_asset": "GOOG", "quote_asset": "USD", "margin_asset": "USD", "order_time_in_force": ["GTC", "IOC", "FOK"], "order_types": ["LIMIT", "MARKET", "ALO"], "default_max_leverage": 20, "market_hours": { "tz": "America/New_York", "monday": { "open": "04:00:00", "close": "20:00:00" }, "tuesday": { "open": "04:00:00", "close": "20:00:00" }, "wednesday": { "open": "04:00:00", "close": "20:00:00" }, "thursday": { "open": "04:00:00", "close": "20:00:00" }, "friday": { "open": "04:00:00", "close": "20:00:00" } } } ] } ``` # Public Trades Source: https://docs.qfex.com/websocket/channels/mds/trades QFEX provides a **realtime stream of executed trades** across all symbols via websocket. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} { "type": "subscribe", "channels": ["trade"], "symbols": ["AAPL-USD", "US500-USD"] } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["trade"], "symbols": ["US500-USD"] # or ["*"] } ws.send(json.dumps(sub)) def on_message(ws, message): data = json.loads(message) print("Trade update:", json.dumps(data, indent=2)) def on_error(ws, error): print("Error:", error) def on_close(ws, close_status_code, close_msg): print("Closed:", close_status_code, close_msg) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close, ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["trade"], symbols: ["US500-USD"], // or ["*"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { try { const data = JSON.parse(msg.toString()); console.log("Trade update:", data); } catch (e) { console.error("Parse error:", e); } }); ws.on("error", (err) => console.error("WS error:", err)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "fmt" "log" "os" "os/signal" "github.com/gorilla/websocket" ) func main() { c, _, err := websocket.DefaultDialer.Dial("wss://mds.qfex.com", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() sub := map[string]interface{}{ "type": "subscribe", "channels": []string{"trade"}, "symbols": []string{"US500-USD"}, // or []string{"*"} } if err := c.WriteJSON(sub); err != nil { log.Fatal("write:", err) } done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("Trade update: %s\n", message) } }() // keep running until Ctrl+C interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) <-interrupt } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class TradeWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("wss://mds.qfex.com") .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { String sub = "{\"type\":\"subscribe\",\"channels\":[\"trade\"],\"symbols\":[\"US500-USD\"]}"; webSocket.send(sub); } @Override public void onMessage(WebSocket webSocket, String text) { System.out.println("Trade update: " + text); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(request, listener); // Keep JVM alive try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "type": "trade", "trade_id": "ac928c66-ca53-498f-9c13-a110027a60e8", "sequence": 50, "time": "2014-11-07T08:19:27.028459Z", "symbol": "AAPL-USD", "size": "5.23512", "price": "400.23", "side": "sell", "execution_type": "NEW" } ``` Please see [Enums](/api-reference/enums) for further details on `execution_type` and others. ### Unsubscribe (optional) ```json theme={null} { "type": "unsubscribe", "channels": ["trade"], "symbols": ["US500-USD"] } ``` *** **Notes** * Messages are pushed in realtime as trades occur. * Supports multiple symbols or a wildcard `*`. * Fields mirror REST and gRPC trade objects. # Underlier Price Source: https://docs.qfex.com/websocket/channels/mds/underlier QFEX provides a **pulsed underlier price stream**, aggregated across multiple exchanges.\ It is used in the **funding calculation** for perpetual markets. Outside of extended market hours, the underlier price will be returned with `source: internal`. See [`/qfex/contract-specifications#oracle-pricing`](/qfex/contract-specifications#oracle-pricing) for oracle details and [`/qfex/funding`](/qfex/funding) for funding-hour behavior. ## How it works Connect to the public websocket: * URL: **wss\://mds.qfex.com** Then send a subscribe message: ```json theme={null} {"type": "subscribe","channels": ["underlier"],"symbols": ["AAPL-USD","US500-USD"]} ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket def on_open(ws): sub = { "type": "subscribe", "channels": ["underlier"], "symbols": ["US500-USD"] # or ["*"] } ws.send(json.dumps(sub)) def on_message(ws, message): data = json.loads(message) print("Underlier update:", json.dumps(data, indent=2)) def on_error(ws, error): print("Error:", error) def on_close(ws, close_status_code, close_msg): print("Closed:", close_status_code, close_msg) if __name__ == "__main__": ws = websocket.WebSocketApp( "wss://mds.qfex.com", on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close, ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const ws = new WebSocket("wss://mds.qfex.com"); ws.on("open", () => { const sub = { type: "subscribe", channels: ["underlier"], symbols: ["US500-USD"], // or ["*"] }; ws.send(JSON.stringify(sub)); }); ws.on("message", (msg) => { try { const data = JSON.parse(msg.toString()); console.log("Underlier update:", data); } catch (e) { console.error("Parse error:", e); } }); ws.on("error", (err) => console.error("WS error:", err)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "fmt" "log" "os" "os/signal" "github.com/gorilla/websocket" ) func main() { c, _, err := websocket.DefaultDialer.Dial("wss://mds.qfex.com", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() sub := map[string]interface{}{ "type": "subscribe", "channels": []string{"underlier"}, "symbols": []string{"US500-USD"}, // or []string{"*"} } if err := c.WriteJSON(sub); err != nil { log.Fatal("write:", err) } done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("Underlier update: %s\n", message) } }() // keep running until Ctrl+C interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) <-interrupt } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class UnderlierWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("wss://mds.qfex.com") .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { String sub = "{\"type\":\"subscribe\",\"channels\":[\"underlier\"],\"symbols\":[\"US500-USD\"]}"; webSocket.send(sub); } @Override public void onMessage(WebSocket webSocket, String text) { System.out.println("Underlier update: " + text); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(request, listener); // Keep JVM alive try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "type": "underlier", "sequence": 50, "time": "2014-11-07T08:19:27.028459Z", "symbol": "AAPL-USD", "price": "400.23", "source": "external" } ``` ### Unsubscribe (optional) ```json theme={null} {"type":"unsubscribe","channels":["underlier"],"symbols":["US500-USD"]} ``` *** **Notes** * Pulsed stream (aggregated over multiple exchanges). * Used in funding rate calculation. * Outside extended hours, prices may continue with `source: internal`. # Order Entry — Add Order Source: https://docs.qfex.com/websocket/channels/trade/add_order Order entry is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Add Order ```json theme={null} { "type": "add_order", "params": { "symbol": "AAPL-USD", "side": "BUY", "order_type": "LIMIT", "order_time_in_force": "GTC", "quantity": 1, "price": 200, "take_profit": 0, "stop_loss": 0, "reduce_only": 0 } } ``` ## Parameters | Field | Type | Required | Description | | --------------------- | ------ | -------------- | ---------------------------------------------------------------------------------------------- | | `symbol` | string | ✅ | The market symbol (e.g. `AAPL-USD`). | | `side` | enum | ✅ | Order direction. See [OrderDirection](/api-reference/enums#orderdirection). | | `order_type` | enum | ✅ | Type of order. See [OrderType](/api-reference/enums#ordertype). | | `order_time_in_force` | enum | ✅ | Time in force policy. See [OrderTimeInForce](/api-reference/enums#ordertimeinforce). | | `quantity` | number | ✅ | Quantity of the order. Must respect lot size and min/max limits (see reference data). | | `price` | number | ⚠️ (Limit/ALO) | Price for limit/ALO orders. Ignored for market orders. Must respect tick size and price bands. | | `take_profit` | number | Optional | Optional take-profit price. Set `0` if unused. | | `stop_loss` | number | Optional | Optional stop-loss price. Set `0` if unused. | | `client_order_id` | string | Optional | Optional client-assigned ID for tracking orders. If empty, one is generated. | > ⚠️ Notes: > > * `price` is required for `LIMIT` and `ALO` orders, but ignored for `MARKET`. > * Tick size, lot size, and min/max order quantity are symbol-specific. See **Reference Data API**. > * An order may be rejected with [OrderStatus](/api-reference/enums#orderstatus) codes if parameters are invalid. ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2) Sub to order responses # https://docs.qfex.com/websocket/channels/trade/order send(ws, {"type": "subscribe", "params": {"channels": ["order_responses"]}}) # 3) Add order send(ws, { "type": "add_order", "params": { "symbol": "AAPL-USD", "side": "BUY", "order_type": "LIMIT", "order_time_in_force": "GTC", "quantity": 1, "price": 200, "take_profit": 0, # Optional "stop_loss": 0, # Optional "resuce_only": True # Optional } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print(m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws const WebSocket = require("ws"); const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { // 1) Authenticate // https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works ws.send(JSON.stringify({"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}})); // 2) Sub to order responses // https://docs.qfex.com/websocket/channels/trade/order ws.send( JSON.stringify({ type: "subscribe", params: { channels: ["order_responses"] }, }) ); }); // 3) Add order ws.send(JSON.stringify({ type: "add_order", params: { symbol: "AAPL-USD", side: "BUY", order_type: "LIMIT", order_time_in_force: "GTC", quantity: 1, price: 200, take_profit: 0, // Optional stop_loss: 0, // Optional reduce_only: true // Optional } })); }); ws.on("message", (m) => console.log(m.toString())); ws.on("error", (e) => console.error("WS error:", e)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2) Sub to order responses // https://docs.qfex.com/websocket/channels/trade/order mustWriteJSON(c, map[string]any{ "type": "subscribe", "params": map[string]any{"channels": []string{"order_responses"}}, }) // 3) Add order mustWriteJSON(c, map[string]any{ "type": "add_order", "params": map[string]any{ "symbol": "AAPL-USD", "side": "BUY", "order_type": "LIMIT", "order_time_in_force": "GTC", "quantity": 1, "price": 200, "take_profit": 0, // Optional "stop_loss": 0, // Optional "reduce_only": true, // Optional }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class AddOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY") .build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // 1) Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // 2) Sub to order responses // https://docs.qfex.com/websocket/channels/trade/order ws.send("{\"type\":\"subscribe\",\"params\":{\"channels\":[\"order_responses\"]}}"); // 3) Add order ws.send("{\"type\":\"add_order\",\"params\":{\"symbol\":\"AAPL-USD\",\"side\":\"BUY\",\"order_type\":\"LIMIT\",\"order_time_in_force\":\"GFD\",\"quantity\":1,\"price\":200,\"take_profit\":0,\"stop_loss\":0}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response When you place an order, you will receive an `order_response` with status `ACK`: ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "ACK", "quantity": 1.0, "price": 200.0, "take_profit": 0.0, "stop_loss": 0.0, "side": "BUY", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 1.0, "trade_id": null } } ``` # Order Entry — Add TWAP Source: https://docs.qfex.com/websocket/channels/trade/add_twap TWAP order entry is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Add TWAP ```json theme={null} { "type": "add_twap", "params": { "symbol": "AAPL-USD", "side": "BUY", "total_quantity": 10, "num_orders": 5, "order_interval_secs": 30, "reduce_only": false, "client_twap_id": "rebalance-aapl-001" } } ``` ## Parameters | Field | Type | Required | Description | | --------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------- | | `symbol` | string | ✅ | The market symbol (for example `AAPL-USD`). | | `side` | enum | ✅ | TWAP direction. See [OrderDirection](/api-reference/enums#orderdirection). | | `total_quantity` | number | ✅ | Total quantity to execute across the full TWAP. It is validated against the symbol's minimum child-order size requirement. | | `num_orders` | number | ✅ | Number of child orders the engine will schedule. | | `order_interval_secs` | number | ✅ | Delay in seconds between child orders. | | `reduce_only` | bool | ✅ | If `true`, the TWAP may only reduce an existing position. | | `client_twap_id` | string | Optional | Optional client-assigned TWAP identifier for tracking and cancellation. | > ⚠️ Notes: > > * TWAP orders are submitted to `trade.qfex.com` using the `add_twap` incoming message. > * A successful TWAP is returned as `twap_response` and also appears in `all_orders_response.twaps`. > * TWAPs can be cancelled with `cancel_order` using `cancel_order_id_type` set to `twap_id` or `client_twap_id`. > * The account must satisfy the same T\&C requirements as standard order entry. ## Validation Rules The server validates `add_twap` requests before forwarding them to the TWAP service. | Rule | Behavior | | --------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | Symbol must be active | Inactive or unknown symbols are rejected. | | `order_interval_secs >= 30` | The minimum interval is **30 seconds**. | | `num_orders >= 2` | A TWAP must contain at least **2 child orders**. | | `total_quantity / num_orders >= min_quantity` | The average child order size must not fall below the symbol's `min_quantity`. | | `client_twap_id` length | If provided, it must be within the same configured min/max length limits used for `client_order_id`. | Additional implementation notes: * `total_quantity` is scaled using the symbol quantity precision before validation. * The current validation shown here does **not** document any explicit requirement that `total_quantity` align to `lot_size`, only that the average child size is not below `min_quantity`. * Errors from local validation are returned as `err` with `error_code: "invalid_parameter"` and a descriptive `message`. ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) send(ws, { "type": "add_twap", "params": { "symbol": "AAPL-USD", "side": "BUY", "total_quantity": 10, "num_orders": 5, "order_interval_secs": 30, "reduce_only": False, "client_twap_id": "rebalance-aapl-001" } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print(m), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { hmac: { public_key: "qfex_pub_xxxxx", nonce: "c0ffee...", unix_ts: 1760545414, signature: "5f2e...", }, }, })); ws.send(JSON.stringify({ type: "add_twap", params: { symbol: "AAPL-USD", side: "BUY", total_quantity: 10, num_orders: 5, order_interval_secs: 30, reduce_only: false, client_twap_id: "rebalance-aapl-001", }, })); }); ws.on("message", (m) => console.log(m.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}}, }) mustWriteJSON(c, map[string]any{ "type": "add_twap", "params": map[string]any{ "symbol": "AAPL-USD", "side": "BUY", "total_quantity": 10, "num_orders": 5, "order_interval_secs": 30, "reduce_only": false, "client_twap_id": "rebalance-aapl-001", }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class AddTwapWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY") .build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\":\"auth\",\"params\":{\"hmac\":{\"public_key\":\"qfex_pub_xxxxx\",\"nonce\":\"c0ffee...\",\"unix_ts\":1760545414,\"signature\":\"5f2e...\"}}}"); ws.send("{\"type\":\"add_twap\",\"params\":{\"symbol\":\"AAPL-USD\",\"side\":\"BUY\",\"total_quantity\":10,\"num_orders\":5,\"order_interval_secs\":30,\"reduce_only\":false,\"client_twap_id\":\"rebalance-aapl-001\"}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## TWAP Response Shape Successful TWAP requests are returned as a `twap_response` object: ```json theme={null} { "twap_response": { "twap_id": "0c7c8e4d-f67e-4aa5-9c64-36a1a622ac35", "client_twap_id": "rebalance-aapl-001", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "status": "ENGINE_STATUS", "symbol": "AAPL-USD", "total_quantity": 10, "filled_quantity": 0, "average_fill_price": 0, "total_num_orders": 5, "order_interval_secs": 30, "reduce_only": false, "side": "BUY", "updated_at": 1760545414.123, "created_at": 1760545414.123 } } ``` | Field | Type | Description | | --------------------- | -------------- | ----------------------------------------------------------- | | `twap_id` | string | Server-generated TWAP identifier. | | `client_twap_id` | string or null | Optional client-provided TWAP identifier. | | `user_id` | string | Account identifier for the TWAP owner. | | `status` | string | Current engine status for the TWAP. | | `symbol` | string | Market symbol. | | `total_quantity` | number | Total requested quantity across the TWAP. | | `filled_quantity` | number | Quantity already filled. | | `average_fill_price` | number | Average execution price across all fills so far. | | `total_num_orders` | number | Total number of scheduled child orders. | | `order_interval_secs` | number | Interval between child orders in seconds. | | `reduce_only` | bool | Whether the TWAP is reduce-only. | | `side` | enum | TWAP direction. | | `updated_at` | number or null | Last update timestamp in seconds with fractional precision. | | `created_at` | number or null | Creation timestamp in seconds with fractional precision. | # Authenticate Source: https://docs.qfex.com/websocket/channels/trade/authenticate Connections to `trade.qfex.com` require authentication. You must authenticate **within 1 minute** of connecting or the server will close the connection. Authentication uses an HMAC-SHA256 signature or a valid JWT token. ## How it works 1. Connect to **wss\://trade.qfex.com?api\_key=YOUR\_PUBLIC\_KEY**. 2. Generate a cryptographically secure random nonce (hex encoded, max 100 characters) and capture the current Unix timestamp. 3. Build the string `${nonce}:${unix_ts}` and compute an HMAC-SHA256 using your secret key. Hex-encode the result to get the signature. 4. Send the auth payload with the `hmac` block shown below. The nonce must be unique within a 15 minute window. 5. If you want the authenticated Trade WebSocket session to use a subaccount, include an optional `account_id` field alongside either `hmac` or `jwt`. When omitted, the connection uses the primary account. ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }, "account_id": "11111111-1111-1111-1111-111111111111" } } ``` Alternatively, authenticate with a JWT: ```json theme={null} { "type": "auth", "params": { "jwt": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImNiYzVmZWNmLTlhODItNGFlNy04NDFkLTBkMTdjMjUzMWM3OCIsInR5cCI6IkpXVCJ9...", "account_id": "11111111-1111-1111-1111-111111111111" } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import hashlib import hmac import json import secrets import time import websocket PUB_KEY = "qfex_pub_xxxxx" SECRET_KEY = "qfex_secret_yyyyyy" def build_auth_message(): nonce = secrets.token_hex(16) unix_ts = int(time.time()) payload = f"{nonce}:{unix_ts}".encode() signature = hmac.new(SECRET_KEY.encode(), payload, hashlib.sha256).hexdigest() return { "type": "auth", "params": { "hmac": { "public_key": PUB_KEY, "nonce": nonce, "unix_ts": unix_ts, "signature": signature, } }, } def on_open(ws): ws.send(json.dumps(build_auth_message())) def on_message(_, message): print("Message:", message) def on_error(_, error): print("Error:", error) def on_close(_, code, reason): print("Closed:", code, reason) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=" + PUB_KEY, on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close, ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import crypto from "crypto"; import WebSocket from "ws"; const pubKey = "qfex_pub_xxxxx"; const secretKey = "qfex_secret_yyyyyy"; function buildAuthMessage() { const nonce = crypto.randomBytes(16).toString("hex"); const unixTs = Math.floor(Date.now() / 1000); const payload = `${nonce}:${unixTs}`; const signature = crypto .createHmac("sha256", secretKey) .update(payload) .digest("hex"); return { type: "auth", params: { hmac: { public_key: pubKey, nonce, unix_ts: unixTs, signature, }, }, }; } const ws = new WebSocket(`wss://trade.qfex.com?api_key=${pubKey}`); ws.on("open", () => { ws.send(JSON.stringify(buildAuthMessage())); }); ws.on("message", (msg) => { console.log("Message:", msg.toString()); }); ws.on("error", (err) => console.error("WS error:", err)); ws.on("close", (code, reason) => { console.log("Closed:", code, reason?.toString() ?? ""); }); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "log" "os" "os/signal" "time" "github.com/gorilla/websocket" ) func main() { pubKey := "qfex_pub_xxxxx" secretKey := []byte("qfex_secret_yyyyyy") c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key="+pubKey, nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() nonceBytes := make([]byte, 16) if _, err := rand.Read(nonceBytes); err != nil { log.Fatal("nonce:", err) } nonce := hex.EncodeToString(nonceBytes) unixTs := time.Now().Unix() message := fmt.Sprintf("%s:%d", nonce, unixTs) h := hmac.New(sha256.New, secretKey) h.Write([]byte(message)) signature := hex.EncodeToString(h.Sum(nil)) auth := map[string]any{ "type": "auth", "params": map[string]any{ "hmac": map[string]any{ "public_key": pubKey, "nonce": nonce, "unix_ts": unixTs, "signature": signature, }, }, } if err := c.WriteJSON(auth); err != nil { log.Fatal("write auth:", err) } go func() { for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("Message: %s\n", message) } }() interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) <-interrupt } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.concurrent.TimeUnit; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import okhttp3.*; public class AuthWs { private static final String PUB_KEY = "qfex_pub_xxxxx"; private static final String SECRET_KEY = "qfex_secret_yyyyyy"; public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("wss://trade.qfex.com?api_key=" + PUB_KEY) .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response response) { ws.send(buildAuthPayload()); } @Override public void onMessage(WebSocket ws, String text) { System.out.println("Message: " + text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(request, listener); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } } private static String buildAuthPayload() { SecureRandom random = new SecureRandom(); byte[] nonceBytes = new byte[16]; random.nextBytes(nonceBytes); String nonce = bytesToHex(nonceBytes); long unixTs = System.currentTimeMillis() / 1000; String data = nonce + ":" + unixTs; String signature; try { Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); mac.init(keySpec); signature = bytesToHex(mac.doFinal(data.getBytes(StandardCharsets.UTF_8))); } catch (Exception e) { throw new IllegalStateException("Unable to sign payload", e); } return String.format( "{\"type\":\"auth\",\"params\":{\"hmac\":{\"public_key\":\"%s\",\"nonce\":\"%s\",\"unix_ts\":%d,\"signature\":\"%s\"}}}", PUB_KEY, nonce, unixTs, signature); } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } } ``` ## Example Response ```json theme={null} { "type": "auth", "result": "success" } ``` After the client successfully authenticates, the server keeps the connection alive by periodically sending heartbeat messages in the form of [WebSocket ping frames](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#pings_and_pongs_the_heartbeat_of_websockets). # Subscribe — Balances Source: https://docs.qfex.com/websocket/channels/trade/balance Subscribe to the **balances** channel to receive pulsed account balance updates.\ Messages are pushed every **1 second**. ## 1) Authenticate Send this immediately after connecting to `wss://trade.qfex.com?api_key=YOUR_API_KEY`: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Subscribe ```json theme={null} { "type": "subscribe", "params": { "channels": ["balances"] } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2) Subscribe to balances send(ws, {"type": "subscribe", "params": {"channels": ["balances"]}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const API_KEY = "YOUR_API_KEY"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "subscribe", params: { channels: ["balances"] } }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ws.on("error", (e) => console.error("WS error:", e)); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2) Subscribe to balances mustWriteJSON(c, map[string]any{ "type": "subscribe", "params": map[string]any{"channels": []string{"balances"}}, }) // Read messages (optional) for { _, data, err := c.ReadMessage() if err != nil { log.Fatal("read:", err) } log.Println(string(data)) } } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class BalancesSub { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder().url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"subscribe\",\"params\":{\"channels\":[\"balances\"]}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Responses ```json theme={null} { "subscribed": "balances" } ``` ```json theme={null} { "balance_response": { "id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "deposit": 9990000000.0, "realised_pnl": 0.0, "order_margin": 0.0, "position_margin": 0.0, "unrealised_pnl": 0.0, "net_funding": 0.0, "available_balance": 9990000000.0 } } ``` Balance updates are **pulsed every 10 seconds**. # Cancel All Orders Source: https://docs.qfex.com/websocket/channels/trade/cancel_all_orders You can cancel **all active orders** for your account (optionally filtered by **symbol**) over **WebSocket** using the `cancel_all_orders` message. ## Example Request ```json theme={null} { "type": "cancel_all_orders", "params": { "symbol": "AAPL-USD" } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Cancel all orders send(ws, {"type": "cancel_all_orders", "params": {}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Cancel all orders ws.send(JSON.stringify({ type: "cancel_all_orders", params: {} })); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Cancel all orders mustWriteJSON(c, map[string]any{ "type": "cancel_all_orders", "params": map[string]any{}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class CancelAllOrdersWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // Cancel all orders ws.send("{\"type\":\"cancel_all_orders\",\"params\":{}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response Every cancelled order will generate an **order\_response** with status `CANCELLED`. ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "CANCELLED", "quantity": 1.0, "price": 200.0, "side": "BUY", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "my-client-oid", "quantity_remaining": 1.0, "trade_id": null } } ``` This cancels **all open orders across all symbols** for the authenticated account, unless a `symbol` is specified. If you only want to cancel specific orders by ID, use the [Cancel Order](/websocket/channels/trade/cancel_order) endpoint instead. # Cancel On Disconnect Source: https://docs.qfex.com/websocket/channels/trade/cancel_on_disconnect Mark a WebSocket session with cancel-on-disconnect to make sure the trade engine closes **every open order** for the account (not just orders placed via this connection) if the connection drops unexpectedly. The flag is scoped to a single connection, so you need to opt in again whenever you reconnect. Send a `cancel_on_disconnect` message with `cancel_on_disconnect` set to `true` immediately after authenticating on any connection you want protected. ## Example Request ```json theme={null} { "type": "cancel_on_disconnect", "params": { "cancel_on_disconnect": true } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json import websocket API_KEY = "YOUR_API_KEY" def send(ws, payload): ws.send(json.dumps(payload)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Enable cancel-on-disconnect for this connection send(ws, {"type": "cancel_on_disconnect", "params": {"cancel_on_disconnect": True}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, message: print("Message:", message), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const API_KEY = "YOUR_API_KEY"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Enable cancel-on-disconnect for this connection ws.send( JSON.stringify({ type: "cancel_on_disconnect", params: { cancel_on_disconnect: true }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Enable cancel-on-disconnect for this connection mustWriteJSON(c, map[string]any{ "type": "cancel_on_disconnect", "params": map[string]any{"cancel_on_disconnect": true}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class CancelAllOrdersWs { private static final String API_KEY = "YOUR_API_KEY"; public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=" + API_KEY) .build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response response) { // Authenticate ws.send("{\"type\":\"auth\",\"params\":{\"api_key\":\"" + API_KEY + "\"}}"); // Enable cancel-on-disconnect for this connection ws.send("{\"type\":\"cancel_on_disconnect\",\"params\":{\"cancel_on_disconnect\":true}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, listener); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException interrupted) { Thread.currentThread().interrupt(); } } } ``` ## Example Response Cancelling with this flag immediately returns an **order\_response** event for each order with status `CANCELLED`. ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "CANCELLED", "quantity": 1.0, "price": 200.0, "side": "BUY", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "my-client-oid", "quantity_remaining": 1.0, "trade_id": null } } ``` Enabling cancel-on-disconnect cancels **all open orders across all symbols** for the authenticated account. If you only want to cancel specific orders, use the [Cancel Order](/websocket/channels/trade/cancel_order) endpoint instead. # Order Entry — Cancel Order Source: https://docs.qfex.com/websocket/channels/trade/cancel_order Order cancellation is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Cancel Order You can cancel by **`order_id`**, **`client_order_id`**, **`twap_id`**, or **`client_twap_id`** by setting the `order_id` field and using `cancel_order_id_type` to specify how the value should be interpreted. * `order_id` — always a **UUID v4** and **unique**. Cancels exactly one order. * `client_order_id` — **not guaranteed unique**. Cancels **all orders for that symbol** that share this client order id. * `twap_id` — server-generated TWAP id. Cancels the matching TWAP. * `client_twap_id` — client-supplied TWAP id. Cancels the matching TWAP for that symbol. ### Cancel by order id (single order) ```json theme={null} { "type": "cancel_order", "params": { "order_id": "REPLACE_WITH_ORDER_UUID_V4", "symbol": "AAPL-USD", "cancel_order_id_type": "order_id" } } ``` ### Cancel by client order id (may cancel multiple) ```json theme={null} { "type": "cancel_order", "params": { "order_id": "my-client-oid-123", "symbol": "AAPL-USD", "cancel_order_id_type": "client_order_id" } } ``` ### Cancel by TWAP id ```json theme={null} { "type": "cancel_order", "params": { "order_id": "0c7c8e4d-f67e-4aa5-9c64-36a1a622ac35", "symbol": "AAPL-USD", "cancel_order_id_type": "twap_id" } } ``` ### Cancel by client TWAP id ```json theme={null} { "type": "cancel_order", "params": { "order_id": "rebalance-aapl-001", "symbol": "AAPL-USD", "cancel_order_id_type": "client_twap_id" } } ``` ## Parameters | Field | Type | Required | Description | | ---------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------- | | `order_id` | string | Optional | UUID v4 of the order to cancel. Required if `cancel_order_id_type` = `"order_id"`. Cancels exactly one order. | | `client_order_id` | string | Optional | Client-specified ID to cancel orders. Required if `cancel_order_id_type` = `"client_order_id"`. May cancel multiple orders. | | `symbol` | string | ✅ | Market symbol of the order(s) (e.g. `AAPL-USD`). | | `cancel_order_id_type` | enum | ✅ | Must be one of `"order_id"`, `"client_order_id"`, `"twap_id"`, or `"client_twap_id"`. Tells the engine how to interpret the ID. | > ⚠️ Notes: > > * Put the identifier value in the `order_id` field for all four modes. The engine uses `cancel_order_id_type` to decide whether that value is an order id, client order id, TWAP id, or client TWAP id. > * `order_id` is always unique (UUID v4). > * `client_order_id` is not guaranteed unique and may cancel multiple orders for the same symbol. > * `twap_id` and `client_twap_id` are used to cancel TWAPs. > * Responses will include [OrderStatus](/api-reference/enums#orderstatus) codes, e.g. `CANCELLED`, `NO_SUCH_ORDER`, or `REJECTED`. ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket API_KEY = "YOUR_API_KEY" ORDER_ID = "REPLACE_WITH_ORDER_UUID_V4" # for order_id flow CLIENT_OID = "my-client-oid-123" # for client_order_id flow def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2a) Cancel by order_id (exactly one order) send(ws, { "type": "cancel_order", "params": { "order_id": ORDER_ID, "symbol": "AAPL-USD", "cancel_order_id_type": "order_id" } }) # 2b) Cancel by client_order_id (may cancel multiple) # send(ws, { # "type": "cancel_order", # "params": { # "client_order_id": CLIENT_OID, # "symbol": "AAPL-USD", # "cancel_order_id_type": "client_order_id" # } # }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print(m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws const WebSocket = require("ws"); const API_KEY = "YOUR_API_KEY"; const ORDER_ID = "REPLACE_WITH_ORDER_UUID_V4"; // for order_id flow const CLIENT_OID = "my-client-oid-123"; // for client_order_id flow const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { // 1) Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // 2a) Cancel by order_id (exactly one order) ws.send( JSON.stringify({ type: "cancel_order", params: { order_id: ORDER_ID, symbol: "AAPL-USD", cancel_order_id_type: "order_id", }, }) ); // 2b) Cancel by client_order_id (may cancel multiple) // ws.send(JSON.stringify({ // type: "cancel_order", // params: { // client_order_id: CLIENT_OID, // symbol: "AAPL-USD", // cancel_order_id_type: "client_order_id" // } // })); }); ws.on("message", (m) => console.log(m.toString())); ws.on("error", (e) => console.error("WS error:", e)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2a) Cancel by order_id (exactly one order) mustWriteJSON(c, map[string]any{ "type": "cancel_order", "params": map[string]any{ "order_id": "REPLACE_WITH_ORDER_UUID_V4", "symbol": "AAPL-USD", "cancel_order_id_type": "order_id", }, }) // 2b) Cancel by client_order_id (may cancel multiple) // mustWriteJSON(c, map[string]any{ // "type": "cancel_order", // "params": map[string]any{ // "client_order_id": "my-client-oid-123", // "symbol": "AAPL-USD", // "cancel_order_id_type": "client_order_id", // }, // }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class CancelOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY") .build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // 1) Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // 2a) Cancel by order_id (exactly one order) ws.send("{\"type\":\"cancel_order\",\"params\":{\"order_id\":\"REPLACE_WITH_ORDER_UUID_V4\",\"symbol\":\"AAPL-USD\",\"cancel_order_id_type\":\"order_id\"}}"); // 2b) Cancel by client_order_id (may cancel multiple) // ws.send("{\"type\":\"cancel_order\",\"params\":{\"client_order_id\":\"my-client-oid-123\",\"symbol\":\"AAPL-USD\",\"cancel_order_id_type\":\"client_order_id\"}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response Placing an order returns `ACK`. Cancelling it returns the same structure but with status `CANCELLED`. ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "CANCELLED", "quantity": 1.0, "price": 200.0, "take_profit": 0.0, "stop_loss": 0.0, "side": "BUY", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 1.0, "trade_id": null } } ``` # Order Entry — Close Position Source: https://docs.qfex.com/websocket/channels/trade/close_position Closing a position is performed over **WebSocket**.\ This command instructs the engine to place a `LIMIT IOC` order on the **opposite side** of your current position, pegged near the mark price to maximise the chance of a complete close-out.\ The engine automatically sizes the order to match your open position, so you always close in full. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Close a Position ```json theme={null} { "type": "close_position", "params": { "symbol": "AAPL-USD" } } ``` ## Parameters | Field | Type | Required | Description | | -------- | ------ | -------- | ----------------------------------------------------------------- | | `symbol` | string | ✅ | Market symbol whose position you want to close (e.g. `AAPL-USD`). | > ⚠️ Notes: > > * The generated order is always `LIMIT` + `IOC`, reduce-only, and inherits the appropriate closing side. > * Subscribe to [`fills`](/websocket/channels/trade/fills) to receive executions. > * Subscribe to [`order_responses`](/websocket/channels/trade/order) to receive final status updates. ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2) Close position send(ws, { "type": "close_position", "params": { "symbol": "AAPL-USD", }, }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print(m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws const WebSocket = require("ws"); const API_KEY = "YOUR_API_KEY"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { // 1) Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // 2) Close position ws.send( JSON.stringify({ type: "close_position", params: { symbol: "AAPL-USD", }, }) ); }); ws.on("message", (m) => console.log(m.toString())); ws.on("error", (e) => console.error("WS error:", e)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2) Close position mustWriteJSON(c, map[string]any{ "type": "close_position", "params": map[string]any{ "symbol": "AAPL-USD", }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class ClosePositionWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY") .build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // 1) Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // 2) Close position ws.send("{\"type\":\"close_position\",\"params\":{\"symbol\":\"AAPL-USD\"}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Responses You will receive an `order_response` acknowledgement immediately, followed by fill updates (if any). ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "ACK", "quantity": 2.0, "price": 199.8, "take_profit": 0.0, "stop_loss": 0.0, "side": "SELL", "type": "LIMIT", "time_in_force": "IOC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 2.0 } } ``` ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "FILLED", "quantity": 2.0, "price": 199.75, "take_profit": 0.0, "stop_loss": 0.0, "side": "SELL", "type": "LIMIT", "time_in_force": "IOC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 0.0 } } ``` Any unfilled remainder is cancelled automatically because the engine always uses `IOC`. If you have no open position for the symbol, the command is rejected. # Subscribe — Fills Source: https://docs.qfex.com/websocket/channels/trade/fills Subscribe to the **fills** channel to receive real-time fill updates for executed trades.\ Messages are pushed in **realtime**. ## 1) Authenticate Send this immediately after connecting to `wss://trade.qfex.com?api_key=YOUR_API_KEY`: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Subscribe ```json theme={null} { "type": "subscribe", "params": { "channels": ["fills"] } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2) Subscribe to fills send(ws, {"type": "subscribe", "params": {"channels": ["fills"]}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const API_KEY = "YOUR_API_KEY"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "subscribe", params: { channels: ["fills"] }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ws.on("error", (e) => console.error("WS error:", e)); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2) Subscribe to fills mustWriteJSON(c, map[string]any{ "type": "subscribe", "params": map[string]any{"channels": []string{"fills"}}, }) // Read messages (optional) for { _, data, err := c.ReadMessage() if err != nil { log.Fatal("read:", err) } log.Println(string(data)) } } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class FillsSub { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder().url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"subscribe\",\"params\":{\"channels\":[\"fills\"]}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Responses ```json theme={null} { "subscribed": "fills" } ``` ```json theme={null} { "fill_response": { "trade_id": "REDACTED", "user_id": "REDACTED", "symbol": "US100-USD", "price": 25242.0, "quantity": 0.004, "side": "SELL", "aggressor_side": "SELL", "order_id": "0aeae7d0-4a6e-4672-ad69-82b8811d4e0b", "fee": 0.00045, "order_type": "MARKET", "tif": "IOC", "order_price": 25547.0, "client_order_id": "REDACTED", "remaining_quantity": 0.0, "take_profit": 0.0, "stop_loss": 0.0, "execution_type": "NEW", "timestamp": 1769439642.8484282, "realised_pnl": 0.0 } } ``` Fill updates are **live**. # Get Available Leverage Levels Source: https://docs.qfex.com/websocket/channels/trade/get_available_leverage You can request the leverage levels available for each symbol for your account. You cannot change the leverage level if you have any open orders or a non zero position. Leverage management is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## Example Request ```json theme={null} { "type": "get_available_leverage_levels", "params": { "limit": 10, "offset": 0 } } ``` * `limit` *(optional)* — maximum number of leverage records to return (default **1000**) * `offset` *(optional)* — pagination offset (default **0**) ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Request user trades send(ws, {"type": "get_available_leverage_levels", "params": {"limit": 10, "offset": 0}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "get_available_leverage_levels", params: { limit: 10, offset: 0 }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Get user leverage mustWriteJSON(c, map[string]any{ "type": "get_available_leverage_levels", "params": map[string]any{"limit": 10, "offset": 0}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class GetUserTradesWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"get_available_leverage_levels\",\"params\":{\"limit\":10,\"offset\":0}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "available_leverage_levels_response": [ { "id": "04349aaf-b29c-456d-b255-7b9de6e180c4", "symbol": "META-USD", "initial_margin": 1.0, "maintenance_margin": 0.6666666666666666, "max_notional": 195000.0, "leverage": "1" }, { "id": "9dc9cc77-5222-47f3-80fe-16d48fa1082e", "symbol": "META-USD", "initial_margin": 0.5, "maintenance_margin": 0.3333333333333333, "max_notional": 190000.0, "leverage": "2" } ] } ``` # Get Leverage Levels Source: https://docs.qfex.com/websocket/channels/trade/get_leverage You can request the leverage levels applied for each symbol for your account. You cannot change the leverage level if you have any open orders or a non zero position. Leverage management is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## Example Request ```json theme={null} { "type": "get_user_leverage", "params": { "limit": 10, "offset": 0 } } ``` * `limit` *(optional)* — maximum number of leverage records to return (default **1000**) * `offset` *(optional)* — pagination offset (default **0**) ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Request user trades send(ws, {"type": "get_user_leverage", "params": {"limit": 10, "offset": 0}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "get_user_leverage", params: { limit: 10, offset: 0 }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Get user leverage mustWriteJSON(c, map[string]any{ "type": "get_user_leverage", "params": map[string]any{"limit": 10, "offset": 0}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class GetUserTradesWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"get_user_leverage\",\"params\":{\"limit\":10,\"offset\":0}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "user_leverage_response": [ { "id": "96eedb94-bf74-4efe-bd64-82e7a541c7f4", "symbol": "META-USD", "initial_margin": 0.05, "maintenance_margin": 0.03333333333333333, "max_notional": 100000.0, "leverage": "20" } ] } ``` # Get Order Source: https://docs.qfex.com/websocket/channels/trade/get_order You can request a specific order by its `order_id` for the authenticated account. ## Example Request ```json theme={null} { "type": "get_order", "params": { "symbol": "US500-USD", "order_id": "57cc1941-8ad1-4df3-b34c-bb556518befc" } } ``` * `symbol` *(required)* — the symbol for the order * `order_id` *(required)* — the order ID to retrieve ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Get order send(ws, {"type": "get_order", "params": {"symbol": "AAPL-USD", "order_id": "57cc1941-8ad1-4df3-b34c-bb556518befc"}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Get order ws.send( JSON.stringify({ type: "get_order", params: { symbol: "AAPL-USD", order_id: "57cc1941-8ad1-4df3-b34c-bb556518befc", }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Get order mustWriteJSON(c, map[string]any{ "type": "get_order", "params": map[string]any{"symbol": "AAPL-USD", "order_id": "57cc1941-8ad1-4df3-b34c-bb556518befc"}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class GetOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // Get order ws.send("{\"type\":\"get_order\",\"params\":{\"symbol\":\"AAPL-USD\",\"order_id\":\"57cc1941-8ad1-4df3-b34c-bb556518befc\"}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "all_orders_response": { "orders": [ { "order_id": "2f05173c-992a-426b-bcaf-6b341644bb62", "symbol": "GOOG-USD", "status": "ACK", "quantity": 2.708, "price": 251.25, "take_profit": 0.0, "stop_loss": 0.0, "side": "SELL", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "7a257796-a9c1-49bd-a80b-bcccdc81c103", "quantity_remaining": 2.708, "update_time": 1758208770.5512846, "trade_id": null } ], "stop_orders": [] } } ``` Only **open orders** (including partially filled) are returned. Filled and fully cancelled orders are not included. # Get User Orders Source: https://docs.qfex.com/websocket/channels/trade/get_user_orders You can request all **open orders** (including partially filled orders) and active **TWAPs** for the authenticated account. ## Example Request ```json theme={null} { "type": "get_user_orders", "params": { "limit": 10, "offset": 0, "symbol": "AAPL-USD" } } ``` * `limit` *(optional)* — maximum number of orders to return (default **1000**) * `offset` *(optional)* — pagination offset (default **0**) * `symbol` *(optional)* — symbol to filter by. Will return all orders if not specified. ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Request user orders send(ws, {"type": "get_user_orders", "params": {"limit": 10, "offset": 0, "symbol": "AAPL-USD"}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Get user orders ws.send( JSON.stringify({ type: "get_user_orders", params: { limit: 10, offset: 0, symbol: "AAPL-USD" }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Get user orders mustWriteJSON(c, map[string]any{ "type": "get_user_orders", "params": map[string]any{"limit": 10, "offset": 0, "symbol": "AAPL-USD"}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class GetUserOrdersWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // Get user orders ws.send("{\"type\":\"get_user_orders\",\"params\":{\"limit\":10,\"offset\":0,\"symbol\":\"AAPL-USD\"}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "all_orders_response": { "orders": [ { "order_id": "2f05173c-992a-426b-bcaf-6b341644bb62", "symbol": "GOOG-USD", "status": "ACK", "quantity": 2.708, "price": 251.25, "take_profit": 0.0, "stop_loss": 0.0, "side": "SELL", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "7a257796-a9c1-49bd-a80b-bcccdc81c103", "quantity_remaining": 2.708, "update_time": 1758208770.5512846, "trade_id": null } ], "twaps": [ { "twap_id": "0c7c8e4d-f67e-4aa5-9c64-36a1a622ac35", "client_twap_id": "rebalance-aapl-001", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "status": "ENGINE_STATUS", "symbol": "GOOG-USD", "total_quantity": 5, "filled_quantity": 1, "average_fill_price": 251.25, "total_num_orders": 5, "order_interval_secs": 30, "reduce_only": false, "side": "SELL", "updated_at": 1758208770.5512846, "created_at": 1758208700.5512846 } ] } } ``` Only **open orders** and active **TWAPs** are returned. Filled and fully cancelled orders are not included. # Get User Trades Source: https://docs.qfex.com/websocket/channels/trade/get_user_trades You can request the most recent **executed trades** (fills) for the authenticated account. ## Example Request ```json theme={null} { "type": "get_user_trades", "params": { "limit": 10, "offset": 0, "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "start_ts": 1746900000, "end_ts": 1746908400 } } ``` * `limit` *(optional)* — maximum number of trades to return (default **1000**) * `offset` *(optional)* — pagination offset (default **0**) * `order_id` *(optional)* — filter trades by a specific exchange order ID * `start_ts` *(optional)* — filter trades from this Unix timestamp (inclusive) * `end_ts` *(optional)* — filter trades up to this Unix timestamp (inclusive) ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Request user trades with optional filters send(ws, { "type": "get_user_trades", "params": { "limit": 10, "offset": 0, "start_ts": 1746900000, "end_ts": 1746908400 } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "get_user_trades", params: { limit: 10, offset: 0, start_ts: 1746900000, end_ts: 1746908400, }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Get user trades with optional filters mustWriteJSON(c, map[string]any{ "type": "get_user_trades", "params": map[string]any{ "limit": 10, "offset": 0, "start_ts": 1746900000, "end_ts": 1746908400, }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class GetUserTradesWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"get_user_trades\",\"params\":{\"limit\":10,\"offset\":0,\"start_ts\":1746900000,\"end_ts\":1746908400}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "user_trades": [ { "trade_id": "92adf4db-1e48-40cf-9e2a-b0ecf079a16a", "symbol": "AAPL-USD", "price": 200.0, "quantity": 1.0, "aggressor_side": "BUY", "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "client_order_id": "my-client-oid", "fee": 0.002, "timestamp": 1746908400 } ], "count": 1 } ``` Only **executed trades (fills)** are returned. Open orders that have not filled are excluded. # Order Entry — Modify Order Source: https://docs.qfex.com/websocket/channels/trade/modify_order Orders can be modified over **WebSocket**.\ Only **`price`**, **`quantity`**, **`take_profit`**, and **`stop_loss`** may be changed. * You **must** specify the order’s **`order_id`** (UUID v4). * You **must** specify the **`symbol`**. * You **must** specify the **`side`**. * You **must** specify the **`order_type`**. * `client_order_id` cannot be used for modifies. ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Modify Order ```json theme={null} { "type": "modify_order", "params": { "order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "side": "BUY", "quantity": 2, "price": 200, "take_profit": 200, "stop_loss": 150 } } ``` ## Parameters | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------------------------------------------------------------------- | | `order_id` | string | ✅ | UUID v4 of the order to modify. | | `symbol` | string | ✅ | The market symbol (e.g. `AAPL-USD`). | | `side` | enum | ✅ | Must match the original order’s side. See [OrderDirection](/api-reference/enums#orderdirection). | | `order_type` | enum | ✅ | Must match the original order’s type. See [OrderType](/api-reference/enums#ordertype). | | `quantity` | number | Optional | New order quantity. Must respect symbol lot size, min, and max constraints. | | `price` | number | Optional | New price for limit/ALO orders. Ignored for market orders. Must respect tick size and price bands. | | `take_profit` | number | Optional | Updated take-profit price. Set `0` if unused. | | `stop_loss` | number | Optional | Updated stop-loss price. Set `0` if unused. | > ⚠️ Notes: > > * Only `price`, `quantity`, `take_profit`, and `stop_loss` may be modified. > * `client_order_id` cannot be used for modifies. > * **The `order_id` changes on modification.** The response will contain a **new** `order_id`. The old `order_id` is replaced. This is because multiple in-flight amends are not currently supported. > * Modifications that would cause an invalid state (e.g. reducing below partially filled quantity) will be rejected with [OrderStatus](/api-reference/enums#orderstatus) codes such as `CANNOT_MODIFY_PARTIAL_FILL` or `CANNOT_MODIFY_NO_SUCH_ORDER`. ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Modify order send(ws, { "type": "modify_order", "params": { "order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "side": "BUY", "order_type": "LIMIT", "quantity": 2, "price": 200, "take_profit": 200, "stop_loss": 150 } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Modify order ws.send( JSON.stringify({ type: "modify_order", params: { order_id: "510333ac-3f7b-4d88-934a-4396d48824cc", symbol: "AAPL-USD", side: "BUY", order_type: "LIMIT", quantity: 2, price: 200, take_profit: 200, stop_loss: 150, }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Modify order mustWriteJSON(c, map[string]any{ "type": "modify_order", "params": map[string]any{ "order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "side": "BUY", "order_type": "LIMIT", "quantity": 2, "price": 200, "take_profit": 200, "stop_loss": 150, }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class ModifyOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // Modify order ws.send("{\"type\":\"modify_order\",\"params\":{\"order_id\":\"510333ac-3f7b-4d88-934a-4396d48824cc\",\"symbol\":\"AAPL-USD\",\"side\":\"BUY\",\"order_type\":\"LIMIT\",\"original_quantity\":1,\"quantity\":2,\"price\":200,\"take_profit\":200,\"stop_loss\":150}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response When an order is successfully modified, you receive the same `order_response` object as with add, but with status **`MODIFIED`** and a **new** `order_id` (the old one is replaced). ```json theme={null} { "order_response": { "order_id": "88888888-4444-4444-4444-1234567890ab", "symbol": "AAPL-USD", "status": "MODIFIED", "quantity": 2.0, "price": 200.0, "take_profit": 200.0, "stop_loss": 150.0, "side": "BUY", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 2.0, "trade_id": null } } ``` # Subscribe — Order Responses Source: https://docs.qfex.com/websocket/channels/trade/order Subscribe to the **order\_responses** channel to receive order responses.\ Messages are pushed in **realtime**. ## 1) Authenticate Send this immediately after connecting to `wss://trade.qfex.com?api_key=YOUR_API_KEY`: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Subscribe ```json theme={null} { "type": "subscribe", "params": { "channels": ["order_responses"] } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2) Subscribe to order responses send(ws, {"type": "subscribe", "params": {"channels": ["order_responses"]}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws import WebSocket from "ws"; const API_KEY = "YOUR_API_KEY"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "subscribe", params: { channels: ["order_responses"] }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ws.on("error", (e) => console.error("WS error:", e)); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2) Subscribe to order responses mustWriteJSON(c, map[string]any{ "type": "subscribe", "params": map[string]any{"channels": []string{"order_responses"}}, }) // Read messages (optional) for { _, data, err := c.ReadMessage() if err != nil { log.Fatal("read:", err) } log.Println(string(data)) } } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class BalancesSub { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder().url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"subscribe\",\"params\":{\"channels\":[\"order_responses\"]}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Responses ```json theme={null} { "subscribed": "order_responses" } ``` ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "ACK", "quantity": 1.0, "price": 200.0, "take_profit": 0.0, "stop_loss": 0.0, "side": "BUY", "type": "LIMIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 1.0, "trade_id": null } } ``` Order responses are **live**. # Subscribe — Positions Source: https://docs.qfex.com/websocket/channels/trade/positions Subscribe to the **positions** channel to receive pulsed position updates for all symbols.\ Messages are pushed every **1 second**. ## 1) Authenticate ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Subscribe ```json theme={null} { "type": "subscribe", "params": { "channels": ["positions"] } } ``` ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) send(ws, {"type": "subscribe", "params": {"channels": ["positions"]}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const API_KEY = "YOUR_API_KEY"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "subscribe", params: { channels: ["positions"] } }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) mustWriteJSON(c, map[string]any{ "type": "subscribe", "params": map[string]any{"channels": []string{"positions"}}, }) for { _, data, err := c.ReadMessage() if err != nil { log.Fatal("read:", err) } log.Println(string(data)) } } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class PositionsSub { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder().url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"subscribe\",\"params\":{\"channels\":[\"positions\"]}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Responses ```json theme={null} { "subscribed": "positions" } ``` ```json theme={null} { "position_response": { "id": "c003ad60-ded4-401b-9b4c-e255a53d32ea", "symbol": "AAPL-USD", "position": 0.0, "margin_alloc": 0.0, "realised_pnl": 0.0, "unrealised_pnl": 0.0, "net_funding": 0.0, "open_orders": 0.0, "open_quantity": 0.0, "leverage": 20.0, "initial_margin": 0.05, "maintenance_margin": 0.03333333333333333, "average_price": 0.0 } } ``` Position updates are **pulsed every 10 seconds**. # Set Leverage Source: https://docs.qfex.com/websocket/channels/trade/set_leverage You can set the leverage level for each symbol for your account. You cannot change the leverage level if you have any open orders or a non zero position. Leverage management is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## Example Request ```json theme={null} { "type": "set_user_leverage", "params": { "symbol": "AAPL-USD", "leverage": 20.0 } } ``` * `symbol` — the symbol to set the leverage for * `leverage` — the leverage level to set ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Set leverage send(ws, {"type": "set_user_leverage", "params": {"symbol": "AAPL-USD", "leverage": 20.0}}) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); ws.send( JSON.stringify({ type: "set_user_leverage", params: { symbol: "AAPL-USD", leverage: 20.0 }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Set leverage mustWriteJSON(c, map[string]any{ "type": "set_user_leverage", "params": map[string]any{"symbol": "AAPL-USD", "leverage": 20.0}, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class GetUserTradesWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); ws.send("{\"type\":\"set_user_leverage\",\"params\":{\"symbol\":\"AAPL-USD\",\"leverage\":20.0}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response ```json theme={null} { "ack_response": true } ``` # Order Entry — Add Stop Order Source: https://docs.qfex.com/websocket/channels/trade/stop_add_order Order entry is performed over **WebSocket**. * **Endpoint:** `wss://trade.qfex.com?api_key=YOUR_API_KEY` * **Authenticate within 1 minute of connecting.** ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Add Order Adding a stop order follows the same pattern as adding a typical order. The direction given must be the eventual direction of the triggered order that is placed into the book. TAKE\_PROFIT and STOP\_LOSS orders cannot exceed your current position, attempting to do this could cause your order to be rejected or other stop orders to be cancelled. ```json theme={null} { "type": "add_order", "params": { "symbol": "AAPL-USD", "side": "BUY", "order_type": "TAKE_PROFIT", "order_time_in_force": "GTC", "quantity": 1, "price": 200 } } ``` ## Parameters | Field | Type | Required | Description | | --------------------- | ------ | -------- | ------------------------------------------------------------------------------ | | `symbol` | string | ✅ | The market symbol (e.g. `AAPL-USD`). | | `side` | enum | ✅ | Order direction. See [OrderDirection](/api-reference/enums#orderdirection). | | `order_type` | enum | ✅ | Type of order. See [OrderType](/api-reference/enums#ordertype). | | `order_time_in_force` | enum | ✅ | Time in force policy. Required for legacy reasons, the value will not be read. | | `quantity` | number | ✅ | Quantity of the order. Must respect lot size but not min/max limits. | | `price` | number | ✅ | Price for when the order is triggered. | > ⚠️ Notes: > > * Tick size, lot size, and min/max order quantity are symbol-specific. See **Reference Data API**. > * An order may be rejected with [OrderStatus](/api-reference/enums#orderstatus) codes if parameters are invalid. ## Sample Code ```python python theme={null} # Python (websocket-client) # pip install websocket-client import json import websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # 1) Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # 2) Add stop order send(ws, { "type": "add_order", "params": { "symbol": "AAPL-USD", "side": "BUY", "order_type": "TAKE_PROFIT", "order_time_in_force": "GTC", "quantity": 1, "price": 200 } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print(m), on_error=lambda _, e: print("Error:", e), on_close=lambda *_: print("Closed"), ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) // npm i ws const WebSocket = require("ws"); const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("open", () => { // 1) Authenticate ws.send( JSON.stringify({ type: "auth", params: { api_key: "YOUR_API_KEY" } }) ); // 2) Add stop order ws.send( JSON.stringify({ type: "add_order", params: { symbol: "AAPL-USD", side: "BUY", order_type: "TAKE_PROFIT", order_time_in_force: "GTC", quantity: 1, price: 200, }, }) ); }); ws.on("message", (m) => console.log(m.toString())); ws.on("error", (e) => console.error("WS error:", e)); ws.on("close", (code, reason) => console.log("Closed:", code, reason?.toString()) ); ``` ```go go theme={null} // Go (gorilla/websocket) // go get github.com/gorilla/websocket package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // 1) Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // 2) Add stop order mustWriteJSON(c, map[string]any{ "type": "add_order", "params": map[string]any{ "symbol": "AAPL-USD", "side": "BUY", "order_type": "TAKE_PROFIT", "order_time_in_force": "GTC", "quantity": 1, "price": 200, }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) // Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") import java.util.concurrent.TimeUnit; import okhttp3.*; public class AddOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS) .build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY") .build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // 1) Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // 2) Add stop order ws.send("{\"type\":\"add_order\",\"params\":{\"symbol\":\"AAPL-USD\",\"side\":\"BUY\",\"order_type\":\"TAKE_PROFIT\",\"order_time_in_force\":\"GTC\",\"quantity\":1,\"price\":200}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } @Override public void onFailure(WebSocket ws, Throwable t, Response r) { System.err.println("WS error: " + t.getMessage()); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response When you place an order, you will receive an `order_response` with status `ACK`: ```json theme={null} { "order_response": { "order_id": "5b309929-206f-40ec-804d-cbe46e81afc1", "symbol": "AAPL-USD", "status": "ACK", "quantity": 1.0, "price": 200.0, "take_profit": 0.0, "stop_loss": 0.0, "side": "BUY", "type": "TAKE_PROFIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 1.0 } } ``` # Order Entry — Cancel Stop Order Source: https://docs.qfex.com/websocket/channels/trade/stop_cancel_order Stop Orders can be cancelled over **WebSocket**. * You **must** specify the stop\_order's **`stop_order_id`** (UUID v4). ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Cancel Order ```json theme={null} { "type": "cancel_stop_order", "params": { "stop_order_id": "510333ac-3f7b-4d88-934a-4396d48824cc" } } ``` ## Parameters | Field | Type | Required | Description | | --------------- | ------ | -------- | ------------------------------------ | | `stop_order_id` | string | ✅ | UUID v4 of the stop order to cancel. | ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Cancel stop order send(ws, { "type": "cancel_stop_order", "params": { "stop_order_id": "510333ac-3f7b-4d88-934a-4396d48824cc" } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Cancel stop order ws.send( JSON.stringify({ type: "cancel_stop_order", params: { stop_order_id: "510333ac-3f7b-4d88-934a-4396d48824cc", }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Cancel stop order mustWriteJSON(c, map[string]any{ "type": "cancel_stop_order", "params": map[string]any{ "stop_order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class CancelStopOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // Cancel stop order ws.send("{\"type\":\"cancel_stop_order\",\"params\":{\"stop_order_id\":\"510333ac-3f7b-4d88-934a-4396d48824cc\"}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response When a stop order is successfully cancelled, you receive an `order_response` with status **`CANCELLED`**: ```json theme={null} { "order_response": { "order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "status": "CANCELLED", "quantity": 0.0, "price": 200.0, "side": "BUY", "type": "TAKE_PROFIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 0.0 } } ``` # Order Entry — Modify Stop Order Source: https://docs.qfex.com/websocket/channels/trade/stop_modify_order Stop Orders can be modified over **WebSocket**.\ Only **`price`** and **`quantity`** may be changed. * You **must** specify the stop\_order’s **`stop_order_id`** (UUID v4). * You **must** specify the **`symbol`**. * You **must** specify the **`side`**. * You **must** specify the **`order_type`**. * `client_order_id` cannot be used for modifies. ## 1) Authenticate Send this immediately after you connect: ```json theme={null} { "type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." } } } ``` ## 2) Modify Order ```json theme={null} { "type": "modify_stop_order", "params": { "stop_order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "side": "BUY", "order_type": "TAKE_PROFIT", "quantity": 2, "price": 200 } } ``` ## Parameters | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- | | `stop_order_id` | string | ✅ | UUID v4 of the order to modify. | | `symbol` | string | ✅ | The market symbol (e.g. `AAPL-USD`). | | `side` | enum | ✅ | Must match the original stop order's side. See [OrderDirection](/api-reference/enums#orderdirection). | | `order_type` | enum | ✅ | Must match the original stop order's type. See [OrderType](/api-reference/enums#ordertype). | | `quantity` | number | Optional | New stop order quantity. Must respect symbol lot size, min, and max constraints. | | `price` | number | Optional | New price for when the order is triggered. Must respect tick size but not price bands. | > ⚠️ Notes: > > * Only `price` and `quantity` may be modified. ## Sample Code ```python python theme={null} # Python (websocket-client) import json, websocket API_KEY = "YOUR_API_KEY" def send(ws, obj): ws.send(json.dumps(obj)) def on_open(ws): # Authenticate # https://docs.qfex.com/websocket/channels/trade/authenticate#how-it-works send(ws, {"type": "auth", "params": { "hmac": { "public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..." }}}) # Modify stop order send(ws, { "type": "modify_stop_order", "params": { "stop_order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "side": "BUY", "order_type": "TAKE_PROFIT", "quantity": 2, "price": 200 } }) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=YOUR_API_KEY", on_open=on_open, on_message=lambda _, m: print("Message:", m) ) ws.run_forever() ``` ```javascript node theme={null} // Node.js (ws) import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); const API_KEY = "YOUR_API_KEY"; ws.on("open", () => { // Authenticate ws.send(JSON.stringify({ type: "auth", params: { api_key: API_KEY } })); // Modify stop order ws.send( JSON.stringify({ type: "modify_stop_order", params: { stop_order_id: "510333ac-3f7b-4d88-934a-4396d48824cc", symbol: "AAPL-USD", side: "BUY", order_type: "TAKE_PROFIT", quantity: 2, price: 200, }, }) ); }); ws.on("message", (msg) => console.log("Message:", msg.toString())); ``` ```go go theme={null} // Go (gorilla/websocket) package main import ( "log" "github.com/gorilla/websocket" ) func mustWriteJSON(c *websocket.Conn, v any) { if err := c.WriteJSON(v); err != nil { log.Fatal("write:", err) } } func main() { c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key=YOUR_API_KEY", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Authenticate mustWriteJSON(c, map[string]any{ "type": "auth", "params": map[string]any{"hmac": map[string]any{"public_key": "qfex_pub_xxxxx", "nonce": "c0ffee...", "unix_ts": 1760545414, "signature": "5f2e..."}} }) // Modify stop order mustWriteJSON(c, map[string]any{ "type": "modify_stop_order", "params": map[string]any{ "stop_order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "side": "BUY", "order_type": "TAKE_PROFIT", "quantity": 2, "price": 200, }, }) } ``` ```java java theme={null} // Java (OkHttp WebSocket) import java.util.concurrent.TimeUnit; import okhttp3.*; public class ModifyOrderWs { public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() .pingInterval(20, TimeUnit.SECONDS).build(); Request req = new Request.Builder() .url("wss://trade.qfex.com?api_key=YOUR_API_KEY").build(); WebSocketListener li = new WebSocketListener() { @Override public void onOpen(WebSocket ws, Response r) { // Authenticate ws.send("{\"type\": \"auth\", \"params\": { \"hmac\": { \"public_key\": \"qfex_pub_xxxxx\", \"nonce\": \"c0ffee...\..\", \"unix_ts\": 1760545414, \"signature\": \"5f2e...\" }}}"); // Modify stop order ws.send("{\"type\":\"modify_stop_order\",\"params\":{\"stop_order_id\":\"510333ac-3f7b-4d88-934a-4396d48824cc\",\"symbol\":\"AAPL-USD\",\"side\":\"BUY\",\"order_type\":\"TAKE_PROFIT\",\"quantity\":2,\"price\":200}}"); } @Override public void onMessage(WebSocket ws, String text) { System.out.println(text); } }; client.newWebSocket(req, li); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {} } } ``` ## Example Response When an order is successfully modified, you receive the same `order_response` object as with add, but with status **`MODIFIED`**: ```json theme={null} { "order_response": { "order_id": "510333ac-3f7b-4d88-934a-4396d48824cc", "symbol": "AAPL-USD", "status": "MODIFIED", "quantity": 2.0, "price": 200.0, "side": "BUY", "type": "TAKE_PROFIT", "time_in_force": "GTC", "user_id": "0020ce8e-eaee-480e-8d7f-b9241d756ee5", "client_order_id": "", "quantity_remaining": 2.0 } } ``` # Errors Source: https://docs.qfex.com/websocket/errors All websocket channels may return an **error frame** instead of the expected response. Error frames share a single, consistent schema. ## Error Envelope ```json theme={null} { "err": { "error_code": "RateLimited", "message": "You have exceeded the allowed message rate.", "incoming_message": { "type": "add_order", "params": { "symbol": "AAPL", "side": "BUY", "order_type": "LIMIT", "order_time_in_force": "GTC", "quantity": 10.0, "price": 200.0, "client_order_id": "my-order-001", "take_profit": null, "stop_loss": null } } } } ``` ### Fields | Field | Type | Required | Description | | ------------------ | ----------- | -------- | ---------------------------------------------------------------------------------- | | `error_code` | string | Yes | Machine-readable error code (see list below). Matches server enum variant exactly. | | `message` | string/null | No | Human-readable context. May be `null`. | | `incoming_message` | object/null | No | Echo of the request that caused the error (your original message), when available. | > Note: `incoming_message` uses the same tagged format as requests (`{ "type": "", "params": { ... } }`). ## Error Codes These values map 1:1 to the server enum: | Code | When it happens | Suggested Client Action | | ---------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | `RateLimited` | You’ve exceeded the allowed message rate (weighted per message type). | Backoff and retry later. Consider batching and respecting published limits. | | `InvalidJSONFormat` | Message is not valid JSON or doesn’t match the expected schema. | Validate JSON and schema before sending. Include required fields and correct types/enum values. | | `AlreadyAuthenticated` | You attempted to authenticate again after a successful auth on the same connection. | Do not re-auth on an already authenticated socket. | | `InvalidParameter` | One or more parameters are out of range, missing, or invalid for the specified message. | Correct the parameter(s) and retry. | | `PermissionDenied` | The API key or user lacks permission for the requested action. | Check key scopes/roles; contact support if needed. | | `ServerError` | Unexpected internal error. | Safe to retry after a short delay; if persistent, contact support with timestamp and `incoming_message`. | | `InvalidOrder` | The order is invalid or malformed. | Check order parameters and format; correct the order and retry. | | `InvalidOrderId` | The supplied order ID is invalid. | Check that the order ID is a valid order UUID. | | `KycRequired` | The user must complete KYC before performing this action. | Complete KYC and retry the request. | | `TncRequired` | The user needs to agree to the latest Terms and Conditions. | Agree to the latest Terms and Conditions. | ### Rate limiting notes The server computes **message weight** by the message `"type"` (e.g., `"add_order"`, `"cancel_order"`) and applies limits over a sliding window. Some messages are heavier than others. If you see `RateLimited`, delay and reduce frequency; prefer fewer, larger requests when possible. ## Examples ### 1) Invalid JSON ```json theme={null} { "err": { "error_code": "InvalidJSONFormat", "message": "Expected field `symbol` (string).", "incoming_message": { "type": "add_order", "params": { "side": "BUY", "order_type": "LIMIT", "order_time_in_force": "GTC", "quantity": 10.0, "price": 200.0 } } } } ``` ### 2) Already authenticated ```json theme={null} { "err": { "error_code": "AlreadyAuthenticated", "message": "Connection is already authenticated.", "incoming_message": { "type": "auth", "params": {} } } } ``` ### 3) Invalid parameter ```json theme={null} { "err": { "error_code": "InvalidParameter", "message": "price must be >= min_tick and within price bands.", "incoming_message": { "type": "modify_order", "params": { "symbol": "AAPL", "order_id": "cd1a2b0c-...-f3", "quantity": 10.0, "price": 0.0001, "take_profit": 0.0, "stop_loss": 0.0, "side": "BUY" } } } } ``` ### 4) Permission denied ```json theme={null} { "err": { "error_code": "PermissionDenied", "message": "API key does not allow trading on this account.", "incoming_message": { "type": "transfer_balance", "params": { "amount": 100.0, "to_api_key": "****" } } } } ``` ### 5) Rate limited ```json theme={null} { "err": { "error_code": "RateLimited", "message": "Too many requests. Please retry after 200ms.", "incoming_message": { "type": "cancel_all_orders", "params": {} } } } ``` ### 6) Server error ```json theme={null} { "err": { "error_code": "ServerError", "message": "Unexpected error processing request.", "incoming_message": { "type": "get_user_trades", "params": { "limit": 50 } } } } ``` ## Client Handling Patterns ```python theme={null} import json import websocket def on_message(ws, message): msg = json.loads(message) if msg.get("type") == "error": code = msg.get("error_code") print(f"[ERROR] {code}: {msg.get('message')}") # basic strategy if code == "RateLimited": # implement backoff before retrying your last request return elif code in ("InvalidJSONFormat", "InvalidParameter"): # fix your payload; don't auto-retry return elif code in ("PermissionDenied", "AlreadyAuthenticated"): # adjust flow; no retry return else: # ServerError or unknown: small backoff and optional retry return else: print("OK:", msg) ``` ```javascript theme={null} import WebSocket from "ws"; const ws = new WebSocket("wss://trade.qfex.com?api_key=YOUR_API_KEY"); ws.on("message", (raw) => { const msg = JSON.parse(raw.toString()); if (msg.type === "error") { const { error_code, message } = msg; console.error(`[ERROR] ${error_code}: ${message || ""}`); switch (error_code) { case "RateLimited": // schedule retry w/ backoff break; case "InvalidJSONFormat": case "InvalidParameter": // fix payload, do not blind-retry break; case "PermissionDenied": case "AlreadyAuthenticated": // update client state/flow break; default: // transient server error: optional retry with jitter break; } return; } // handle normal messages… }); ``` ```go theme={null} type ErrorFrame struct { Type string `json:"type"` ErrorCode string `json:"error_code"` Message *string `json:"message,omitempty"` IncomingMessage json.RawMessage `json:"incoming_message,omitempty"` } func handleMessage(raw []byte) { // peek at "type" var meta struct{ Type string `json:"type"` } if err := json.Unmarshal(raw, &meta); err != nil { return } if meta.Type == "error" { var ef ErrorFrame if err := json.Unmarshal(raw, &ef); err == nil { log.Printf("[ERROR] %s: %s", ef.ErrorCode, deref(ef.Message)) // handle per code... } return } // normal flow... } ``` ## Authentication & Errors * **trade.qfex.com** requires authentication within 1 minute of connecting. * Attempting to re-authenticate an already authenticated connection yields `AlreadyAuthenticated`. ## Troubleshooting Checklist 1. Validate JSON (types/enums/required fields). 2. Respect rate limits (reduce burstiness; batch where possible). 3. Ensure your API key has the right permissions. 4. Log `incoming_message` from error frames to quickly reproduce issues. 5. For persistent `ServerError`, contact **[support@qfex.com](mailto:support@qfex.com)** with timestamp and offending `incoming_message`. # Websocket Overview Source: https://docs.qfex.com/websocket/main QFEX provides 2 endpoints for websocket: * [mds.qfex.com](wss://mds.qfex.com) for public market and reference data. * [trade.qfex.com](wss://trade.qfex.com) for order entry and private data. Market Data is public and does not require authentication. Trade requires an API key and a connection must [authenticate](/websocket/channels/trade/authenticate) within 1 minute of connecting. If you want the Trade WebSocket session to operate on a subaccount, include `account_id` in the auth payload. When omitted, the connection uses the primary account. ## Getting Started To access private data or place orders, you must connect to `trade.qfex.com` and authenticate. The following examples show how to connect, authenticate using HMAC-SHA256, and maintain the connection. ```python theme={null} # pip install websocket-client import hashlib import hmac import json import secrets import time import websocket PUB_KEY = "qfex_pub_xxxxx" SECRET_KEY = "qfex_secret_yyyyyy" def build_auth_message(): nonce = secrets.token_hex(16) unix_ts = int(time.time()) payload = f"{nonce}:{unix_ts}".encode() signature = hmac.new(SECRET_KEY.encode(), payload, hashlib.sha256).hexdigest() return { "type": "auth", "params": { "hmac": { "public_key": PUB_KEY, "nonce": nonce, "unix_ts": unix_ts, "signature": signature, } }, } def on_open(ws): print("Connected") ws.send(json.dumps(build_auth_message())) def on_message(ws, message): print("Received:", message) ws = websocket.WebSocketApp( "wss://trade.qfex.com?api_key=" + PUB_KEY, on_open=on_open, on_message=on_message ) ws.run_forever() ``` ```javascript theme={null} // npm i ws import crypto from "crypto"; import WebSocket from "ws"; const pubKey = "qfex_pub_xxxxx"; const secretKey = "qfex_secret_yyyyyy"; function buildAuthMessage() { const nonce = crypto.randomBytes(16).toString("hex"); const unixTs = Math.floor(Date.now() / 1000); const payload = `${nonce}:${unixTs}`; const signature = crypto .createHmac("sha256", secretKey) .update(payload) .digest("hex"); return { type: "auth", params: { hmac: { public_key: pubKey, nonce, unix_ts: unixTs, signature, }, }, }; } const ws = new WebSocket(`wss://trade.qfex.com?api_key=${pubKey}`); ws.on("open", () => { console.log("Connected"); ws.send(JSON.stringify(buildAuthMessage())); }); ws.on("message", (msg) => { console.log("Received:", msg.toString()); }); ``` ```go theme={null} // go get github.com/gorilla/websocket package main import ( "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "log" "time" "github.com/gorilla/websocket" ) func main() { pubKey := "qfex_pub_xxxxx" secretKey := []byte("qfex_secret_yyyyyy") c, _, err := websocket.DefaultDialer.Dial("wss://trade.qfex.com?api_key="+pubKey, nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // Build Auth Message nonceBytes := make([]byte, 16) rand.Read(nonceBytes) nonce := hex.EncodeToString(nonceBytes) unixTs := time.Now().Unix() message := fmt.Sprintf("%s:%d", nonce, unixTs) h := hmac.New(sha256.New, secretKey) h.Write([]byte(message)) signature := hex.EncodeToString(h.Sum(nil)) auth := map[string]any{ "type": "auth", "params": map[string]any{ "hmac": map[string]any{ "public_key": pubKey, "nonce": nonce, "unix_ts": unixTs, "signature": signature, }, }, } c.WriteJSON(auth) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } fmt.Printf("recv: %s\n", message) } } ``` ## Authentication Authentication is required for the `trade.qfex.com` endpoint. 1. **Connect**: Include your public API key as a query parameter: ``` wss://trade.qfex.com?api_key=YOUR_PUBLIC_KEY ``` 2. **Authenticate**: Send an authentication message signed with your secret key within 1 minute. You can use either an **HMAC-SHA256 signature** (recommended) or a valid **JWT token**. For full details on the authentication payload and parameters, see the [Authenticate](/websocket/channels/trade/authenticate) documentation. # MDS Playground Source: https://docs.qfex.com/websocket/mds Single channel for orderbook, trades, candles # API Rate Limits Source: https://docs.qfex.com/websocket/rate This page explains how request throttling works on our **WebSocket trading API**. If you’re writing a client, read this to avoid `RateLimited` errors. ## Summary * Rate limits are **per user** and apply across **all** of your concurrent WebSocket connections. * The limit is **12,000 weight units per 60 seconds**. * We use an **Exponential Moving Average (EMA)** model to smooth bursts rather than a simple per-second counter. * There are **two independent buckets** per user: * **General bucket** for orders, queries, subscriptions, etc. * **Cancel bucket** for cancel-related messages. * Each message type has an internal **weight**. Heavier actions (e.g., placing orders) consume more budget than light ones (e.g., subscribing). > Limits and weights may change over time to protect system stability. Always handle `RateLimited` responses gracefully rather than assuming fixed throughput. *** ## Message weights Current values: | Message | Weight | | -------------------------------- | :----: | | add\_order | 1.0 | | cancel\_order | 1.0 | | modify\_order | 1.0 | | get\_order | 2.0 | | get\_user\_orders | 5.0 | | cancel\_all\_orders | 2.0 | | get\_user\_trades | 0.5 | | subscribe | 0.1 | | unsubscribe | 0.1 | | get\_user\_leverage | 0.1 | | get\_available\_leverage\_levels | 0.1 | | set\_user\_leverage | 0.1 | | cancel\_stop\_order | 1.0 | | modify\_stop\_order | 1.0 | | cancel\_on\_disconnect | 0.1 | The current limit is **12,000 units per 60 seconds** (200 units/sec). An `add_order` (1.0) uses 1 unit, so you can sustainably place \~200 orders/sec. *** ## What’s limited These limits apply to **WebSocket inbound messages** after successful authentication. HTTP endpoints and the initial WebSocket handshake may be subject to separate controls. *** ## How it works We maintain an **EMA of your weighted message rate**. Each incoming message adds its weight; between messages the EMA decays automatically. * If your EMA rises above the allowed threshold for a bucket, the next message for that bucket is rejected with a `RateLimited` error. * The error includes a **retry-after** hint so your client knows when it is safe to try again. Because cancels use a **separate bucket**, you can often cancel even when your general bucket is momentarily saturated (subject to the cancel bucket’s own limits). *** ## Per-user, cross-connection If you open multiple WebSocket connections, their traffic **aggregates** into the same per-user budgets (one general, one cancel). Opening more sockets does **not** increase your effective allowance. *** ## Error you may see When a message is throttled, you’ll receive a unicast error on your WebSocket: ```json theme={null} { "type": "Err", "error_code": "RateLimited", "message": "Rate limit exceeded, retry after N seconds", "incoming_message": {} } ``` Use the `retry after` value as guidance for when to resend. *** ## Client best practices 1. **Backoff with jitter**\ On `RateLimited`, wait the suggested number of seconds **plus a small random jitter** (e.g., 50–200 ms) before retrying. This avoids thundering herds. 2. **Coalesce & batch**\ Prefer fewer, purposeful messages over many tiny ones (especially modifies). 3. **Respect cancel bucket**\ Cancels have their own allowance to help you unwind risk quickly. It’s separate, not unlimited—avoid bursty cancel storms. 4. **Stagger across connections**\ If you run multiple connections, **stagger** bursts. They share the same per-user budgets. 5. **Idempotency**\ Use client order IDs where supported so a retry doesn’t create duplicates if the first attempt actually succeeded server-side. 6. **Subscription hygiene**\ Subscriptions are light but not free. Avoid repeatedly subscribing/unsubscribing in short intervals. *** ## FAQs **Is the limit per IP or per API key?**\ Per **user**. Multiple API keys tied to the same user share the same budgets. **Do reads count against the limit?**\ Yes, but they are lighter than writes. **Can I burst?**\ Short bursts are tolerated due to EMA smoothing. Sustained rates above the threshold will be throttled. **Can I request higher limits?**\ If you have a production use case that requires more throughput, contact us to discuss dedicated quotas. *** ## Change policy We may adjust rate-limit thresholds and message weights from time to time to maintain platform reliability. Such changes do not require client updates, provided your integration handles `RateLimited` responses and performs backoff as described above. # Trade Playground Source: https://docs.qfex.com/websocket/trade Single channel for order commands, positions, balances, fills