# Welcome

Architect is a new, innovative platform for all US futures and options traders, from retail to institutional.\
\
Please [contact us](/user-guide/contact-us) if we can be of any help.


# Getting Started


# Opening an Account

## Individuals <a href="#h_d7442bf85c" id="h_d7442bf85c"></a>

To open an account, visit [app.architect.co](https://app.architect.co/) and select the "Get Started" button. Follow the prompts to create an account and login.

<figure><img src="/files/vpdj87zCub1yVJwU0bJA" alt="" width="375"><figcaption><p><em>Individual Account Creation</em></p></figcaption></figure>

Once you've logged in, you will be guided through the KYC and account verification process. If you need to resume progress on an application, visit <https://app.architect.co/identity-verification> or click the settings icon in the upper right to return to your application.

Architect and our partner FCM, Dorman Trading, are legally required to collect some information about you when opening your account. You will also have a chance to review the various agreements and terms from both Architect and Dorman Trading. As one step in this process, you'll be directed to [Plaid](https://docs.architect.co/architect-user-guide-and-faq/getting-started/onboarding-and-kyc/who-is-plaid) to answer a few identification questions, and returned to continue Architect's account sign-up process afterwards.

After completing the onboarding steps, we will promptly process your application. You will receive an email confirmation when your account is open.

## Institutions <a href="#h_d7442bf85c" id="h_d7442bf85c"></a>

To open an institutional account, reach out to <sales@architect.co>. There are additional KYC and AML requirements for institutions that cannot be completed online.


# Who is Plaid?

Architect uses Plaid as a trusted, established partner to streamline the KYC process. Visit their website to learn more about Plaid and KYC.&#x20;

{% embed url="<https://plaid.com/>" %}

{% embed url="<https://plaid.com/resources/banking/what-is-kyc/>" %}

If Plaid is unable to automatically verify your identity, please [contact us](/user-guide/contact-us) for help.&#x20;

<figure><img src="/files/904qf4KUNEPS18xMX3PV" alt=""><figcaption></figcaption></figure>


# License and Pricing Tiers

The most up-to-date information about the Brokerage User License, including costs, can be found on the [Account ](https://app.architect.co/user/account)page.

## Unverified Account (Paper Trading) <a href="#h_7a8b38dd19" id="h_7a8b38dd19"></a>

Your unverified Architect account provides complimentary access to paper trading (GUI and API) with delayed marketdata.

## Architect Verified Account <a href="#h_7c3a97ad60" id="h_7c3a97ad60"></a>

After completing KYC/AML verificaiton and making a deposit, you will have access to live trading and marketdata. There is no monthly fee for this account and it is subject to the commissions and fees listed [here.](https://www.architect.co/brokerage/pricing)

## Architect Plus <a href="#h_28c4011669" id="h_28c4011669"></a>

To access the full suite of Architect features, individuals can upgrade to the Architect Plus account. The monthly fee is $100, which unlocks access to the following features:

* Reduced commissions
* Unlimited API trading access
* Access to Architect's proprietary execution algorithms

## Architect Institutional <a href="#h_b8e51cca0c" id="h_b8e51cca0c"></a>

If you are an institution interested in onboarding, please contact us at <sales@architect.co> to begin the process.

Architect Institutional offers bespoke pricing based on trading and margin requirements, and includes full, unlimited access to the trading platform.\ <br>


# FAQ


# Do you accept non-US users? Institutions?

While our primary userbase is US individuals, we have limited support for individuals in some areas outside the United States and institutional onboarding. Please [Contact Us](/user-guide/contact-us) for further information.


# Can I use my own FCM? What FCM is right for me?

If you have an existing FCM relationship that you want to use with Architect, please [Contact Us](/user-guide/contact-us) and we will explore the available options! We are often able to facilitate this.&#x20;

If you're creating a new account, the onboarding process will guide you through the FCM account opening process.&#x20;


# My Account


# Login Issues & Password Reset

To reset your password, click "Forgot password" on the login screen and follow the reset instructions.

<figure><img src="/files/GkzGaedGrqZdoMbuGIr4" alt="" width="188"><figcaption></figcaption></figure>

For other login related issues, please [Contact Us](/user-guide/contact-us).


# Statements & Tax Documents


# Account Statements

Your account information is available on the [Statements ](https://app.architect.co/user/statements)page, including daily and monthly statements.&#x20;

In addition, our [FCM ](/user-guide/futures-101/ibs-and-fcms)partners may be required to directly send you account statements, which will typically arrive by e-mail.&#x20;


# Tax Reporting

Your annual tax documents will be available on the Statements page as soon as they are ready.

We rely on our clearing partners to provide accurate tax documentation, and we will make these documents available to users as soon as we receive them from the clearing firm. Architect does not prepare or create tax documents.&#x20;

For further details, including regarding timing and specific documents, please [Contact Us](/user-guide/contact-us).


# Deposits & Withdrawals

Click the Deposit or Withdraw buttons on the Portfolio tab for detailed instructions

<figure><img src="/files/UWR6wzcrII435QnNvWyT" alt=""><figcaption></figcaption></figure>


# Making a Deposit

Visit the [Transfers ](https://app.architect.co/user/transfers)page! Funds can be deposited to your account by linking your bank account and initiating a transfer. Architect uses [Plaid & Orum ](/user-guide/my-account/deposits-and-withdrawals/plaid-and-orum)to allow you to safely and securely deposit funds from your bank account.&#x20;

<figure><img src="/files/vXET2W7WxSXm9T0fliNg" alt=""><figcaption><p>Plaid may require additional verification</p></figcaption></figure>

Once your bank account is successfully linked, it will be available as a dropdown option when clicking the Deposit button, and follow the prompts.&#x20;

Deposits are processed via ACH and typically arrive in a few business days.&#x20;


# Manual ACH or Wire Transfer

As an alternative to using the bank account linking, our FCM partners often support additional funding ramps, such as ACH transfer or a wire transfer. Please [contact us](/user-guide/contact-us) for additional details.&#x20;


# Requesting a Withdrawal

Visit the [Transfers ](https://app.architect.co/user/transfers)page! Architect uses [Plaid & Orum ](/user-guide/my-account/deposits-and-withdrawals/plaid-and-orum)to allow you to safely and securely withdraw funds to your linked bank account.

You can withdraw the Excess Cash in your account, which is the US Dollar balance in excess of the [margin required](/user-guide/futures-101/margin-and-leverage) to support your current futures positions. \
\
Please [Contact Us](/user-guide/contact-us) if you need additional assistance, including if you would like to request a wire transfer or non-linked ACH transfer.&#x20;


# Plaid & Orum

We're partnering with [Plaid ](https://plaid.com/)and [Orum](https://www.orum.io/) to streamline transfers between your bank and your trading account. Both are industry leaders in facilitating safe and secure transactions.&#x20;

Linking your bank account with Architect is the easiest way to Deposit and Withdraw money.&#x20;


# Update My Account Information

If you need to update things like your personal information or contact information, please [Contact Us](/user-guide/contact-us).


# Fees & Commissions

We generate a statement which contains all transactions and associated charges, and will be automatically sent to your registered email address at the end of each day. This statement is also available directly on the platform, see [Account Statements](/user-guide/my-account/statements-and-tax-documents/account-statements)

You can see brokerage user license pricing, commissions, and fees on our [pricing page.](https://www.architect.co/brokerage/pricing)<br>


# Marketdata & Live Quotes

Architect provides live, non-delayed CME marketdata for both top-of-book (L1) and depth-of-book (L2). This is available at no additional charge for Architect Basic, Architect Plus, and Architect's Institutional / Professional users. \
\
Contact us at <sales@architect.co> if you are interested in a professional license.


# Trading Fees & Commissions

Architect charges per-contract commissions based on futures product and Architect account tier.\
\
We additionally pass on costs fees & commissions we incur on your behalf, which generally includes trading fees from the exchange, a regulatory NFA fee, and a clearing fee from the FCM.\
\
These fees are subject to change.

|                                  | Architect Basic | Architect Plus |
| -------------------------------- | --------------- | -------------- |
| Commissions - Futures (standard) | $0.75           | $0.50          |
| Commissions - Futures (micro)    | $0.50           | $0.30          |
| Commissions - Options on Futures | $1.00           | $0.50          |
| Commissions - Event Contracts    | $0.50           | $0.30          |

| Institutional Fee Schedule | Standard   | Micro |
| -------------------------- | ---------- | ----- |
| <=1000 contracts           | $0.80      | $0.30 |
| 1001-10,000                | $0.60      | $0.27 |
| 10,001 - 20,000            | $0.40      | $0.25 |
| >20,000                    | Contact Us |       |


# Architect Platform


# Home Page

From the Home page, you will be able to view markets, trade, configure algorithms, and view your portfolio and custom dashboards. You can also use the Command Bar to search products.&#x20;

<figure><img src="/files/QaWb52SLdIEdHYCgKhWZ" alt=""><figcaption><p>Command Bar</p></figcaption></figure>


# Positions and balances

## Positions

Architect shows the derivatives positions you currently hold. This includes the asset, direction, quantity, entry price, current price, unrealized profit or loss, and the notional size of the position.

## Balances

This shows a breakdown of the cash balances in your account. Your Balance is the settled USD balance, while your Buying Power (also often called Account Equity) includes the [unrealized profit or loss](/user-guide/futures-101/profit-and-loss) from your current open positions.

This section also shows your margin information, including the [Total Margin](/user-guide/futures-101/margin-and-leverage) required to support your open positions and the Excess Cash available in your account for trading or withdrawal. Typically, the Excess Cash will be the difference between your Buying Power and Total Margin requirement.&#x20;


# Orders, trades and algos

## Orders

The Orders section shows a recent history of orders sent. This includes the core order information as well as the status of the order (Fill, Out, Canceled, etc.) and any messages associated with the order (e.g. a reject reason).&#x20;

The Cancel All button will cancel all open orders, and each order can also be canceled from this page.

## Fills

The Fills section shows a history of completed trades in your account.

## Algos

The Algos section shows a brief summary of algorithmic orders, with further details available on the [Algos](/user-guide/architect-platform/algos) page.


# Markets

The Markets page is a dashboard of available products to trade.&#x20;

The default contract to trade will be the front month contract (the contract with the highest volume), but advanced users can also select a specific contract expiry in the dropdown.

There are available filters to narrow by asset type (Agriculture, Crypto, FX, etc).&#x20;


# Trade


# Order Types

Orders can be submitted with differing behaviors depending on the parameters they are sent with, which allow traders better control of their executions in the market.&#x20;

Because of the added risks and unpredictable execution quality, Architect does not natively support Market Orders.&#x20;

## Limit Orders

A limit order is an order with a specified price. A buy order will only be executed at or below the limit price, and a sell order will only be executed at or above the limit price.&#x20;

## Stop Loss / Take Profit

A stop order is an order that does not immediately go live, but instead waits for a price condition to be satisfied before becoming active. These are not supported by every exchange.&#x20;

For a Stop Loss order, managing a long position as an example, the stop loss trigger price will generally be a price below the current market price. If the market falls to the trigger price, a sell order will entered into the market with the specified limit price, which enables the trader to reduce further losses by closing the long position.&#x20;

For a Take Profit order, managing a long position as an example, the take profit trigger price will generally be a price above the current market price. If the market rises to the trigger price, a sell order will be entered into the market with the specified limit price, which enables the trader to realize the gains by closing the long position.&#x20;

## Time in Force (TIF)

Architect currently supports three different choices for Time in Force. Not all are supported by every exchange.

* Good Till Cancel (GTC): These orders remain active until they are completely executed or canceled.
* Good Till Date (GTD): These orders remain active until they are completely executed or canceled. If the specified date is reached, the order will expire and be canceled.
* Immediate or Cancel (IOC): These orders will cancel any remaining portion of the order that does not get immediately filled. Note that for the CME, this is described as a Fill-And-Kill (FAK) order.

## Post-Only

This is a limit order that will only be added to the order book if it does not immediately interact with an existing order, and thus will only be a "maker" and never a "taker". Note that CME does not support this order attribute.

## Ladder

This is Architect's clickable interface for entering limit orders. After specifying an order size, clicking on a price level will send an order to join with the same limit price and direction.&#x20;


# Charting & Technical Analysis

For all your charting and technical analysis needs, we support TradingView charts on the Trade tab.\
\
![](/files/d7xgj9SdKFZkNgQhzBVG)

For assistance in understanding and troubleshooting charts, [please visit TradingView.](https://www.tradingview.com/support/categories/chart/)

{% embed url="<https://www.tradingview.com/support/>" %}


# Trade Analytics

Architect provides a suite of built-in tools to perform post-trade analytics or trade cost analytics (TCA). More details coming soon!


# Margin Rates & Product Info

Margin rates are primarily set by the exchange and are regularly updated. The most up to date margin rates can be found on each Product Info page on the bottom left of the Trade tab. This page also includes some details about the product's specifications.

<figure><img src="/files/c970iELJWd8lLaz4QcQu" alt=""><figcaption><p>An example of the Product Info page for CME's E-Mini S&#x26;P 500 future</p></figcaption></figure>

\
Learn more about [Margin & Leverage](/user-guide/futures-101/margin-and-leverage)


# Algos

Architect provides a suite of order execution algos out-of-the box. See the Algo Guide:

{% embed url="<https://architect-xyz.gitbook.io/architect-algo-guide/>" %}


# Logout

On the [profile page](https://app.architect.co/user/profile) (user profile icon in the top right corner), click "Logout".


# Microsoft Excel Add-In

For users of the Architect trading platform who want access to trading functionality via Excel, we provide an Excel Add-In. This add-in also allows Architect users to connect and see prices, positions, balances, and PnL.

Users should already have an account with Architect, along with an API key and secret.

{% stepper %}
{% step %}

### Create an Architect account if you don't already have one

<https://app.architect.co/login>
{% endstep %}

{% step %}

### Create an API key and secret

<https://app.architect.co/api-keys>
{% endstep %}

{% step %}

### Install the Excel Add-In

{% embed url="<https://excel.architect.co/>" %}
{% endstep %}
{% endstepper %}


# Futures 101


# What is a Future

A futures contract is an agreement to buy or sell a specific quantity of a commodity, financial instrument, or other asset at a predetermined price at a specified time in the future. These contracts are traded on futures exchanges, such as the CME, which act as a marketplace between buyers and sellers.&#x20;

Here are some key features of futures contracts:

1. **Standardization**: Each futures contract is standardized by the exchange in terms of the quantity, and delivery time and location for the underlying asset.
2. **Margin Requirements**: Futures contracts require a margin deposit, which is a fraction of the total contract value. This serves as a performance bond to ensure that each party can fulfill their financial obligations under the contract.
3. **Marking to Market**: The value of a futures contract is marked to market daily. This means the contract's gains and losses are settled at the end of each trading day, with money transferred between the buyer's and seller's accounts to reflect the contract's current market value.
4. **Leverage**: Since only a margin deposit is required to buy or sell a futures contract (rather than the full value of the underlying asset), futures can provide significant leverage. This means that small price movements can lead to large profits or losses relative to the margin amount.
5. **Hedging and Speculation**:
   * **Hedging**: Businesses and investors use futures contracts to hedge against price changes in commodities, currencies, or financial instruments. For example, a farmer might use futures to lock in a price for a crop to protect against a drop in market prices by the time the crop is harvested and sold.
   * **Speculation**: Traders and investors might buy and sell futures contracts to profit from anticipated price movements of the underlying asset, without any intention of taking delivery of the physical commodity or asset.
6. **Obligation to Buy/Sell**: When a futures contract is held to expiration, the buyer is obligated to purchase, and the seller is obligated to deliver the underlying asset at the agreed price, unless they close their positions earlier in the trading period.
7. **Regulation:** In the US, futures trading and exchanges are regulated by the Commodities Futures Trading Commission ([CFTC](https://www.cftc.gov/)).

Futures are used across various sectors including agriculture (e.g., wheat, corn, soybeans), energy (e.g., crude oil, natural gas), metals (e.g., gold, silver), and financial instruments (e.g., stock indices, interest rates). For the full list of futures products and exchanges that Architect supports, visit [Example of Available Products](/user-guide/futures-101/example-of-available-products).


# Why Trade Futures

Trading futures can offer several advantages and opportunities for different types of participants, including hedgers, speculators, and arbitrageurs. Here are some of the primary reasons why individuals and institutions might choose to trade futures:

1. **Hedging Risk**: One of the most common uses of futures is to hedge against price risks. Businesses that depend on certain commodities (like farmers, manufacturers, or airlines) can use futures contracts to lock in prices for these commodities, thereby stabilizing their costs or revenues regardless of market volatility. For example, a cereal manufacturer might purchase wheat futures to secure a stable price for wheat, protecting against potential rising costs.
2. **Speculation**: Futures provide an opportunity for traders to speculate on the future direction of prices of commodities, currencies, indices, or bonds. Since futures offer leverage, even small price movements can lead to significant profits. However, this also increases the risk, as losses can be equally significant.
3. **Leverage**: Futures trading requires a relatively small amount of capital (known as margin) to control a larger amount of the underlying asset. This leverage can amplify profits if the market moves in the trader’s favor, though it also increases potential losses if the market moves against the trader.
4. **Price Discovery**: Futures markets play a crucial role in determining the current and future prices of goods and financial assets through the continuous interaction of buying and selling activities. This price discovery process helps in making the market more transparent and efficient.
5. **Liquidity**: Futures markets are typically very liquid due to the large number of participants and the standardized nature of contracts. This high liquidity makes it easier to enter and exit positions at competitive prices.
6. **Short Selling**: Unlike in many other markets, it is just as easy to sell futures as it is to buy them. This means that traders can profit from falling prices just as easily as they can from rising prices. This capability is particularly important for speculators and also for hedgers who need to protect themselves against a decline in the prices of assets they hold.
7. **No Time Decay**: Unlike options, which lose value over time as they approach expiration due to time decay, futures contracts do not suffer from this as they are agreements to buy or sell an asset at a future date rather than the right to do so.
8. **Arbitrage Opportunities**: Traders can exploit price inefficiencies between related futures contracts or between a futures contract and its underlying spot asset through various arbitrage strategies.&#x20;
9. **Flexible Trading Hours:** Unlike in many other markets, futures exchanges are often available for trading around the clock, giving traders more flexibility and fewer time constraints around their trading. Each exchange and product has published trading hours (e.g. [CME](https://www.cmegroup.com/trading-hours.html)).&#x20;
10. **Tax Advantages:** Futures trading profits are treated differently than some other products from a tax perspective, and this can be an advantage for some traders based on their tax situation.

However, trading futures and using leverage can be highly risky because they amplify both potential profits and losses. Futures contracts require traders to predict price movements of assets with a high degree of accuracy, and even small market fluctuations can result in significant financial losses. Leverage magnifies these risks by allowing traders to control larger positions with a smaller amount of capital, but if the market moves against them, they can quickly lose more than their initial investment, leading to margin calls or even the liquidation of their positions. The combination of these factors means that while the upside potential is high, the downside risk is equally substantial, making it crucial for traders to have a solid risk management strategy in place.


# Profit & Loss

To make or lose money when trading futures:

* **Making Money:**
  1. **Long Position:** Buy a futures contract expecting the price to rise. Sell when the price increases to realize a profit.
  2. **Short Position:** Sell a futures contract expecting the price to fall. Buy back at a lower price to profit from the difference.
* **Losing Money:**

  1. **Long Position:** If the price falls after purchasing, selling at a lower price results in a loss.
  2. **Short Position:** If the price rises after selling, buying back at a higher price incurs a loss.

  Profit or loss is determined by the difference between the entry and exit prices of the futures contracts.

#### Realized vs. Unrealized Profit & Loss

**Realized Profit & Loss:**

* Occurs when a trade is completed.
* The profit or loss is locked in when the position is closed.
* Reflects actual gains or losses that affect one's account balance.

**Unrealized Profit & Loss:**

* Represents potential gains or losses on open positions.
* Changes with market price fluctuations.
* Not locked in until the position is closed.


# Expiration, Settlement, and Roll

At a specified date, a futures contract will cease trading and expire, through a process called final settlement. The exact schedule and mechanism varies by product. Traders have three main choices if they hold a position in a future nearing settlement: close out positions, letting the futures expire, or roll forward to another contract.&#x20;

**Close out positions:** \
This is the simplest option, and appropriate if the trader no longer wants the position or exposure. This requires no special help from anyone like Architect or the Exchange. The trader would buy back any short positions or sell out any long positions, and end with a position of zero going into expiration. \
\
**Letting futures expire:**\
Holding a position in a future through expiration means to go to the final settlement process.&#x20;

* Physically Settled Futures:\
  For some contracts, final expiration requires a physical delivery between the short and long position holders. This is common in agriculture, interest rates, precious metals, and energy futures. **Architect currently does not support expiration of physically settled futures, and open positions approaching expiration may be liquidated without notice.** To avoid physical delivery, expiration here means the earlier of the Last Trade Date and First Notice Date.
* Financial/Cash Settled Futures:\
  For most contracts, delivery takes place financially, meaning as cash based on the final settlement value. Each future's final settlement procedure is published by the exchange, and after this value is known, the futures position is removed from the account and a final profit/loss is booked.&#x20;

**Roll forward to another contract:**\
Rolling forward means to close out the position in the expiring future, and open a new futures position in a later-expiring contract. This is used if the trader wants to maintain the exposure past the original expiration date, and is commonly done a few days before futures expiration.&#x20;


# Margin & Leverage

Margin refers to the amount of money required to open and maintain a futures position. This is set by the exchange and the broker or FCM, and is specific to each futures product based on characteristics like the volatility and risk.&#x20;

**Initial Margin vs Maintenance Margin:** \
The Initial Margin Requirement is the amount of money required to open a new futures position. Once the position is opened, the trader must post at least the Maintenance Margin Requirement in order to keep the position open.&#x20;

Because the margin requirement is typically much less than the full value that underlies the future, futures trading is Leveraged, meaning smaller price moves can have an amplified impact on a traders profits and losses. This is a way in which futures trading is inherently risky, but can have capital efficiency benefits. \
\
In Architect, each product's margin information is available in the [Product Info](/user-guide/architect-platform/trade/margin-rates-and-product-info). \
\
The account's margin status is available in the [Balances](/user-guide/architect-platform/home-page/positions-and-balances).


# Margin Call & Liquidation

If an account's Buying Power (i.e. Account Equity) drops below the Total Margin requirement, the account will be subject to Margin Call and/or Liquidation.

A **Margin Call** is a request for the user to deposit additional funds such that the account value once again meets the margin requirements. Depending on the situation, closing positions can also bring the account back into a margin compliant state.

**Liquidation** occurs when the broker forcibly closes out an investor's positions to bring the account back to the required margin level or to prevent further losses. This typically happens if the investor fails to meet a margin call or if the account equity drops significantly.

The full terms and legal details are available in the account agreements with both Architect and our FCM partners.


# Symbology

Futures symbology is the naming convention that futures symbols use. Traditionally, there are two parts:

* **Symbol Root**\
  The Symbol Root is generally a few characters at the start that identify the type of futures contract you're trading. This is sometimes called a Futures Stem or Contract Code, and sometimes can vary across platforms. Some examples are GC for Gold futures, ES for E-Mini S\&P 500 futures, and CL for Crude Oil futures. See[Example of Available Products](/user-guide/futures-101/example-of-available-products) for a full list.
* **Contract Expiration**\
  The Contract Expiration shows when the future will expire. Traditionally the Month will be represented by a single letter:

  * January - F
  * February - G
  * March - H
  * April - J
  * May - K
  * June - M
  * July - N
  * August - Q
  * September - U
  * October - V
  * November - X
  * December - Z

  Followed by the expiration year as a single digit, e.g. 4 to represent 2024. <br>

So as an example, for the E-Mini S\&P 500 future (ES) expiring in December (Z) 2024 (4), the full symbol is ESZ4.&#x20;

In Architect, futures are categorized by their symbol root as well as the full expiration date.&#x20;

Additionally, Futures Spreads and Event Contracts contain further details that specify the relevant details of those trading instruments.&#x20;


# Example of Available Products

Architect connects with various venues in order to provide a variety of products to trade. \
These include venues like CME, Coinbase Derivatives, and CBoe Futures Exchange. <br>

<table><thead><tr><th>Exchange</th><th>Exchange Product Code</th><th>Product Description</th><th data-hidden>Exchange MIC Code</th><th data-hidden>CQG Contract Symbol</th></tr></thead><tbody><tr><td>CME</td><td>ZF</td><td>5-Year T-Note Futures</td><td>XCBT</td><td>F.US.FVA</td></tr><tr><td>CME</td><td>ZN</td><td>10-Year T-Note Futures</td><td>XCBT</td><td>F.US.TYA</td></tr><tr><td>CME</td><td>ZT</td><td>2-Year T-Note Futures</td><td>XCBT</td><td>F.US.TUA</td></tr><tr><td>CME</td><td>ES</td><td>E-mini S&#x26;P 500 Futures</td><td>XCME</td><td>F.US.EP</td></tr><tr><td>CME</td><td>TN</td><td>Ultra 10-Year U.S. Treasury Note Futures</td><td>XCBT</td><td>F.US.TNA</td></tr><tr><td>CME</td><td>CL</td><td>Crude Oil Futures</td><td>XNYM</td><td>F.US.CLE</td></tr><tr><td>CME</td><td>UB</td><td>Ultra U.S. Treasury Bond Futures</td><td>XCBT</td><td>F.US.ULA</td></tr><tr><td>CME</td><td>NG</td><td>Henry Hub Natural Gas Futures</td><td>XNYM</td><td>F.US.NGE</td></tr><tr><td>CME</td><td>ZB</td><td>U.S. Treasury Bond Futures</td><td>XCBT</td><td>F.US.USA</td></tr><tr><td>CME</td><td>ZC</td><td>Corn Futures</td><td>XCBT</td><td>F.US.ZCE</td></tr><tr><td>CME</td><td>ZS</td><td>Soybean Futures</td><td>XCBT</td><td>F.US.ZSE</td></tr><tr><td>CME</td><td>6E</td><td>Euro FX Futures</td><td>XCME</td><td>F.US.EU6</td></tr><tr><td>CME</td><td>ZL</td><td>Soybean Oil Futures</td><td>XCBT</td><td>F.US.ZLE</td></tr><tr><td>CME</td><td>GC</td><td>Gold Futures</td><td>XCEC</td><td>F.US.GCE</td></tr><tr><td>CME</td><td>RTY</td><td>E-mini Russell 2000 Index Futures</td><td>XCME</td><td>F.US.RTY</td></tr><tr><td>CME</td><td>ZM</td><td>Soybean Meal Futures</td><td>XCBT</td><td>F.US.ZME</td></tr><tr><td>CME</td><td>RB</td><td>RBOB Gasoline Futures</td><td>XNYM</td><td>F.US.RBE</td></tr><tr><td>CME</td><td>ZW</td><td>Chicago SRW Wheat Futures</td><td>XCBT</td><td>F.US.ZWA</td></tr><tr><td>CME</td><td>HO</td><td>NY Harbor ULSD Futures</td><td>XNYM</td><td>F.US.HOE</td></tr><tr><td>CME</td><td>6J</td><td>Japanese Yen Futures</td><td>XCME</td><td>F.US.JY6</td></tr><tr><td>CME</td><td>HG</td><td>Copper Futures</td><td>XCEC</td><td>F.US.CPE</td></tr><tr><td>CME</td><td>HE</td><td>Lean Hog Futures</td><td>XCME</td><td>F.US.HE</td></tr><tr><td>CME</td><td>LE</td><td>Live Cattle Futures</td><td>XCME</td><td>F.US.GLE</td></tr><tr><td>CME</td><td>NQ</td><td>E-mini Nasdaq-100 Futures</td><td>XCME</td><td>F.US.ENQ</td></tr><tr><td>CME</td><td>6M</td><td>Mexican Peso Futures</td><td>XCME</td><td>F.US.MX6</td></tr><tr><td>CME</td><td>KE</td><td>KC HRW Wheat Futures</td><td>XCBT</td><td>F.US.KWE</td></tr><tr><td>CME</td><td>6A</td><td>Australian Dollar Futures</td><td>XCME</td><td>F.US.DA6</td></tr><tr><td>CME</td><td>6B</td><td>British Pound Futures</td><td>XCME</td><td>F.US.BP6</td></tr><tr><td>CME</td><td>6C</td><td>Canadian Dollar Futures</td><td>XCME</td><td>F.US.CA6</td></tr><tr><td>CME</td><td>SI</td><td>Silver Futures</td><td>XCEC</td><td>F.US.SIE</td></tr><tr><td>CME</td><td>YM</td><td>E-mini Dow Jones Industrial Average Index Futures</td><td>XCBT</td><td>F.US.YM</td></tr><tr><td>CME</td><td>6S</td><td>Swiss Franc Futures</td><td>XCME</td><td>F.US.SF6</td></tr><tr><td>CME</td><td>BTC</td><td>Bitcoin Futures</td><td>XCME</td><td>F.US.BTC</td></tr><tr><td>CME</td><td>ETH</td><td>Ether Futures</td><td>XCME</td><td>F.US.ETHR</td></tr><tr><td>CME</td><td>MNQ</td><td>Micro E-mini Nasdaq-100 Index Futures</td><td>XCME</td><td>F.US.MNQ</td></tr><tr><td>CME</td><td>MES</td><td>Micro E-mini S&#x26;P 500 Index Futures</td><td>XCME</td><td>F.US.MES</td></tr><tr><td>CME</td><td>MBT</td><td>Micro Bitcoin Futures</td><td>XCME</td><td>F.US.MBT</td></tr><tr><td>CME</td><td>MET</td><td>Micro Ether Futures</td><td>XCME</td><td>F.US.GMET</td></tr><tr><td>CME</td><td>MGC</td><td>Micro Gold Futures</td><td>XCEC</td><td>F.US.MGC</td></tr><tr><td>CME</td><td>MYM</td><td>Micro E-mini Dow Jones Industrial Average Index Futures</td><td>XCBT</td><td>F.US.MYM</td></tr><tr><td>CME</td><td>MCL</td><td>Micro WTI Crude Oil Futures</td><td>XNYM</td><td>F.US.MCLE</td></tr><tr><td>CME</td><td>M2K</td><td>Micro E-mini Russell 2000 Index Futures</td><td>XCME</td><td>F.US.M2K</td></tr><tr><td>CME</td><td>M6E</td><td>Micro EUR/USD Futures</td><td>XCME</td><td>F.US.M6E</td></tr><tr><td>CME</td><td>SIL</td><td>Micro Silver Futures</td><td>XCEC</td><td>F.US.SIL</td></tr><tr><td>CME</td><td>MHG</td><td>Micro Copper Futures</td><td>XCEC</td><td>F.US.MHG</td></tr><tr><td>CME</td><td>M6A</td><td>Micro AUD/USD Futures</td><td>XCME</td><td>F.US.M6A</td></tr><tr><td>CME</td><td>M6B</td><td>Micro GBP/USD Futures</td><td>XCME</td><td>F.US.M6B</td></tr><tr><td>CME</td><td>MTN</td><td>Micro Ultra 10-Year U.S. Treasury Note Futures</td><td>XCBT</td><td>F.US.MTNA</td></tr><tr><td>CME</td><td>MCD</td><td>Micro CAD/USD Futures</td><td>XCME</td><td>F.US.GMCD</td></tr><tr><td>CME</td><td>MNG</td><td>Micro Henry Hub Natural Gas Futures</td><td>XNYM</td><td>F.US.MNG</td></tr><tr><td>CME</td><td>MWN</td><td>Micro Ultra U.S. Treasury Bond Futures</td><td>XCBT</td><td>F.US.MWNA</td></tr><tr><td>CME</td><td>MSF</td><td>Micro CHF/USD Futures</td><td>XCME</td><td>F.US.MSF</td></tr></tbody></table>


# IBs and FCMs

[Architect](/user-guide/about-us/our-licenses) is regulated as an Independent Introducing Broker. [As described by the National Futures Association](https://www.nfa.futures.org/registration-membership/who-has-to-register/ib.html#:~:text=An%20introducing%20broker%20\(IB\)%20is,customers%20to%20support%20these%20orders.): An introducing broker (IB) is an individual or organization that solicits or accepts orders to buy or sell futures contracts, commodity options, retail off-exchange forex contracts, or swaps but does not accept money or other assets from customers to support these orders.

Architect partners with a variety of Futures Commission Merchants (FCMs) who will hold your account and funds. [As described by the National Futures Association](https://www.nfa.futures.org/registration-membership/who-has-to-register/fcm.html#:~:text=A%20futures%20commission%20merchant%20\(FCM,customers%20to%20support%20such%20orders.): A futures commission merchant (FCM) is an entity that solicits or accepts orders to buy or sell futures contracts, options on futures, retail off-exchange forex contracts or swaps, and accepts money or other assets from customers to support such orders.


# Bitcoin & Cryptocurrency

Digital assets or cryptocurrencies, like Bitcoin (BTC) and Ethereum (ETH), are the underlying asset for some US futures. It's worth noting that the underlying spot cryptocurrency markets are not generally regulated in the same way like US futures exchanges are, and this asset class carries higher risks and volatility. \
\
Architect Financial Derivatives LLC IS A MEMBER OF NFA AND IS SUBJECT TO NFA'S REGULATORY OVERSIGHT AND EXAMINATIONS. HOWEVER, YOU SHOULD BE AWARE THAT NFA DOES NOT HAVE REGULATORY OVERSIGHT AUTHORITY OVER UNDERLYING OR SPOT VIRTUAL CURRENCY PRODUCTS OR TRANSACTIONS OR VIRTUAL CURRENCY EXCHANGES, CUSTODIANS OR MARKETS.\
\
See additional notices about Virtual Currency from the [CFTC ](https://www.cftc.gov/LearnAndProtect/AdvisoriesAndArticles/understand_risks_of_virtual_currency.html)and [NFA](https://www.nfa.futures.org/members/ib/regulatory-obligations/virtual-currency.html).&#x20;


# Tech Support


# Desktop


# Graphs & TradingView

Architect offers three different modes for price graphs, which can be configured on the top right on the Trade tab. In the [Advanced ](/user-guide/tech-support/desktop/simple-and-advanced-layouts)layout, the graphs will take you directly to the TradingView. \
\
![](/files/97Po93x8sA7G7Gj2aeuD)\
![](/files/WkH1uUFgc8h0WMD02rws)

![](/files/NIHIwFtcRkrVmvHXwBuI)


# Simple & Advanced Layouts

Clicking the Gear logo in the top right offers a toggle between our Simple and Advanced layout modes. The core features of Architect are available in both, but the visual style offers different customizations and designs. For example, the trading price charts in Advanced mode is the full TradingView!&#x20;

<figure><img src="/files/6sXE9ZDjw21pySkqz0zI" alt=""><figcaption></figcaption></figure>


# Dark Mode

Dark and light mode are available through the settings menu (gear in top right corner) ![](/files/2VhabZwwOLZ2NXREa4ht)


# Mobile App

Our Mobile App is coming soon on both the Apple and Android stores!&#x20;


# Telegram

Architect supports connecting your Architect account and your Telegram account to access the following trading features through the Telegram App:

* Trading
* Order Management
* Account Summaries

Get started with Architect Brokerage Bot by clicking the link in the Telegram App section of the [Account](https://app.architect.co/user/account) page.


# GraphQL API and Rust SDK

Architect offers multiple ways to programmatically interact with all aspects of the platform. For more, see our dedicated guide:&#x20;

{% embed url="<https://architect-xyz.gitbook.io/architect-api-and-sdk-guide/>" %}


# About Us


# Legal

See our full legal documentation at <https://www.architect.co/legal>


# Safety of Funds

Customer deposits are held with our futures commission merchant (FCM) partners. Each FCM provides a detailed breakdown of their customer safety of funds policies, including up-to-date financial information.&#x20;

Architect does not custody any customer funds.


# Our Licenses

Architect Financial Derivatives LLC ("AFDL") is a Commodity Futures Trading Commission (CFTC)/National Futures Association (NFA) regulated Independent Introducing Broker (IIB).

Information about Architect from the NFA can be found on the [NFA Basic](https://www.nfa.futures.org/BasicNet/basic-profile.aspx?nfaid=xtYexicw%2BVk%3D) website.


# Our Partners

We partner with [Straits](https://us.straitsfinancial.com/about/who-we-are/) as one of our FCMs to custody funds and provide clearing for futures trading.&#x20;

> Straits Financial LLC is a Futures Commission Merchant (FCM) registered with the Commodity Futures Trading Commission (CFTC) and the National Futures Association (NFA). Straits Financial LLC is a subsidiary of Straits Financial Group Pte. Ltd, the brokering division of the CWT Group, a global leading provider of integrated commodity services.

We partner with [Dorman](https://www.dormantrading.com/) as one of our FCMs to custody funds and provide clearing for futures trading.

> Dorman Trading is one of the oldest, family-operated Futures Commission Merchants in the world. With decades of experience spanning three generations, Dorman Trading provides the trading community with exceptional service and support.

We partner with [StoneX](https://www.stonex.com/en/) as one of our FCMs to custody funds and provide clearing for futures trading.

> StoneX Group Inc. (NASDAQ: SNEX) is an institutional-grade financial services franchise, offering advanced digital platforms, end-to-end clearing and execution services, and deep expertise to our clients worldwide.

We partner with [Plaid ](https://plaid.com/what-is-plaid/)to provide a streamlined onboarding & KYC process.

> Plaid is a data network that powers the fintech tools millions of people rely on to live a healthier financial life. We work with thousands of fintech companies like Venmo and SoFi, several of the Fortune 500, and many of the largest banks to make it easy for people to connect their financial accounts to the apps and services they want to use. Plaid’s network covers 12,000 financial institutions across the US, Canada, UK and Europe. Headquartered in San Francisco, the company was founded in 2013 by Zach Perret and William Hockey.

We partner with [CQG ](https://www.cqg.com/about-cqg)as a technology provider for our FCMs and exchanges.

> CQG is the industry's highest-performing solution for integrated trade routing, global market data, and advanced technical analysis tools. CQG partners with more than one hundred Futures Commission Merchant environments and provides Direct Market Access to more than forty-five exchanges through its worldwide network of co-located CQG Hosted Exchange Gateways. CQG’s market data feed consolidates data from over seventy-five sources.


# Contact Us

We'd love to hear from you if you have comments or questions, or if you need other assistance!\
\
Email us at <support@architect.co> or message us by clicking on the bottom right corner <img src="/files/1GwxBepP6vp9eQNUdkxe" alt="" data-size="line">from the trading app.&#x20;


# Introduction

Architect provides several options for programmatic access to marketdata, order entry, portfolio management, and execution algos.

## Creating an API key

To start using the Architect API and SDKs, you will need to create an API key from the Architect UI.

<details>

<summary>Navigate to profile/settings</summary>

<img src="/files/CW8uLl0g5qtwQCywrtfh" alt="" data-size="original">

</details>

<details>

<summary>Create an API key</summary>

<img src="/files/u1ocwQd5jnlMRQFb2jhB" alt="" data-size="original">

</details>

<details>

<summary>Store your key and secret in a secure location</summary>

<img src="/files/dQhg2FtOPzMpV8Xq5ppQ" alt="" data-size="original">

</details>

## Getting started

* [Getting started with Python](/getting-started-with-python)
* [Getting started with Rust](/getting-started-with-rust)


# Getting started with Python

{% embed url="<https://github.com/architect-xyz/architect-py>" %}

{% embed url="<https://pypi.org/project/architect-py/>" fullWidth="false" %}

## Installation

```bash
pip install architect-py
```

## Typechecking

`architect-py` is fully typed, so you can use it with an IDE that supports type checking (e.g. VSCode with the Pylance extension). Generally speaking, the package will work if it typechecks.

## Example

In this example, we'll use the **architect-py** SDK to place a limit order on CME's Micro Ethereum (MET) futures front month contract, 10% below the current best bid.

```python
import asyncio
import time
from decimal import Decimal

from architect_py import AsyncClient, OrderStatus, OrderDir


async def main():
    c = await AsyncClient.connect(
        endpoint="app.architect.co",
        api_key="<api key>",
        api_secret="<api secret>",
        paper_trading=False,
    )

    symbol = "ES 20281215 CME Future/USD"
    venue = "CME"

    # Get ticker for a single instrument
    print()
    print(f"Ticker for {symbol}")
    ticker = await c.get_ticker(symbol=symbol, venue=venue)
    print(f"Best bid: {ticker.bid_price}")
    print(f"Best ask: {ticker.ask_price}")

    # List your FCM accounts
    print()
    print("Your FCM accounts:")
    accounts = await c.list_accounts()
    for account in accounts:
        print(f"{account.account.name}")

    account_id = accounts[0].account.id

    # Place a limit order $100 below the best bid
    best_bid = ticker.bid_price
    if best_bid is None:
        raise ValueError("No bid price available")
    limit_price = best_bid - Decimal(100)
    quantity = Decimal(1)
    account = accounts[0]
    order = None
    
    if (
        input(
            f"Place a limit order to BUY 1 LIMIT {limit_price} on account {account.account.name}? [y/N]"
        )
        == "y"
    ):
        order = await c.place_limit_order(
            symbol=symbol,
            execution_venue=venue,
            dir=OrderDir.BUY,
            quantity=quantity,
            limit_price=limit_price,
            account=str(account_id),
        )
    else:
        raise ValueError("Order was not placed")
    print(f"Order placed with ID: {order.id}")

    # Poll order status until rejected or fully executed
    # After 5 seconds, cancel the order
    i = 0
    while OrderStatus.Open == order.status:
        time.sleep(1)
        print(f"...order state: {order.status}")
        order = await c.get_order(order.id)
        assert order is not None
        i += 1
        if i == 5:
            print("Canceling order")
            await c.cancel_order(order.id)

    # Print final order state
    if OrderStatus.Rejected == order.status:
        print(f"Order was rejected: {order.reject_message}")
    elif OrderStatus.Canceled == order.status:
        print("Order was canceled")
    elif OrderStatus.Out == order.status:
        print(f"Order was filled for qty: {order.filled_quantity}")
        print(f"Average execution price: {order.average_fill_price}")


if __name__ == "__main__":
    asyncio.run(main())
```

## Async vs sync

Using the `AsyncClient` is preferred, but the Python SDK also includes a sync version which can be imported as `from architect_py import Client`. Its interface is identical to the async client with the following exceptions:

* Methods starting with `stream_` are not available
* Methods starting with `subscribe_` are not available
* `orderflow` bidirectional channel is unavailable

When following the documentation, simply omit the `await` keyword from the examples when using the sync client.

## Additional examples

Additional examples can be found in the [GitHub repository](https://github.com/architect-xyz/architect-py/tree/main/examples).


# Getting started with Python (Jupyter)

We recommend using `uv` with the following `pyproject.toml`:

```toml
[project]
dependencies = [
    "architect-py",
    "numpy",
    "pandas",
]
description = "Add your description here"
name = "new-architect-project"
readme = "README.md"
requires-python = ">=3.12"
version = "0.1.0"
```

Then you can use one of the following commands to start a Jupyter notebook or lab session:

* `uv run --with jupyter jupyter notebook`
* `uv run --with jupyter jupyter lab`

Otherwise, in your own python environment, you can simply do

```
pip install architect-py
```

See [here](https://github.com/architect-xyz/architect-py/blob/main/examples/jupyter_example.ipynb) for a comprehensive example of a jupyter notebook.


# Getting started with Rust

{% embed url="<https://github.com/architect-xyz/architect-sdk>" %}

## Installation

```bash
cargo add architect-api
cargo add architect-sdk
```

## Example

```rust
use anyhow::Result;
use architect_sdk::Architect;

#[tokio::main]
async fn main() -> Result<()> {
    // Connect to live trading
    let client = Architect::connect("<api key>", "<api secret>", false).await?;
    
    // Or connect to paper trading
    // let client = Architect::connect("<api key>", "<api secret>", true).await?;
    
    Ok(())
}
```


# Symbology

Symbols identify financial instruments using human-readable identifiers. Architect normalizes symbols across different exchanges, venues, clearing houses, etc. to create a consistent nomenclature across the platform. There are three basic types of symbols:

* **Products** are things that you can hold and have a balance or position in, such as stocks, bonds, futures, options, etc. Examples of products include: BTC Crypto, AAPL US Equity, USD, EUR, GC 20250626 CME Future, etc.
* **Tradable products** are products that identify a trading pair on an exchange or venue. Examples of tradable products include: BTC Crypto/USD, BTC Crypto/ETH Crypto, AAPL US Equity/USD, EUR/USD, GC 20250626 CME Future/USD, etc.
* **Venues** are names for exchanges, clearing firms, etc. Examples of venues include: BINANCE, CME, etc. Venues may sometimes be referred to as marketdata venues or execution venues specifically.

Ultimately, symbols are just string identifiers that try to follow particular patterns, nothing more or less.

## Futures and perpetuals

Product names for futures and perpetuals generally include their issuing venue, as derivative contracts aren't usually fungible between venues. For example, "GC 20250626 CME Future" refers to the CME futures contract, and "BTC-USDT BINANCE Perpetual" refers to the Binance perpetual. OCC cleared options are a notable exception.

### Aliases

For some venues, we provide traditional aliases for products in addition to their Architect normalized names. On CME, you can also refer to "GC 20250626 CME Future" as "GCM5 CME Future" using traditional futures month codes.


# Orderflow

Placing and managing orders requires tracking the state of an order throughout its lifecycle. Architect presents a normalized view of order lifecycle across all supported venues. Expected state transitions are marked by the diagram arrows. States at the bottom of the diagram are considered final and no further  transitions are expected from those states.

<figure><img src="/files/bs1yfJ5hYkfasiBNp6nh" alt=""><figcaption></figcaption></figure>

### Order status descriptions

<table><thead><tr><th width="187.44140625">Order Status</th><th>Description</th></tr></thead><tbody><tr><td>PENDING</td><td>Orders that have been received by Architect begin life as PENDING. Architect will forward the order onto the destination venue/exchange and wait for a reply.</td></tr><tr><td>OPEN</td><td>The order has been received by the venue/exchange and is considered executable/working.</td></tr><tr><td>REJECTED</td><td>An order submitted has been rejected by either the Architect OEMS, or the venue/exchange. Inspect the reject reason or reject message to determine the cause of the rejection.</td></tr><tr><td>CANCELING</td><td>Architect has received a cancel request for this order and is attempting to effect the cancel at the venue/exchange.</td></tr><tr><td>CANCELED</td><td>An order has been confirmed canceled by the venue/exchange.</td></tr><tr><td>OUT</td><td>An order is no longer on the orderbook or otherwise considered non-executable by the venue/exchange; e.g. retirement of a DAY order after the end of a the exchange's trading session.</td></tr><tr><td>RECONCILED_OUT</td><td>Same as the OUT state, except that it was discovered asynchronously by Architect. This might happen in the case of a dropped connection or other downtime event.</td></tr><tr><td>STALE</td><td>Discretionary state that is assigned to an order by Architect if an expected state transition was not observed past some staleness threshold. Indicates a potential problem with the order at the exchange, or a connectivity issue. Users should contact Architect customer support immediately to gain clarity.</td></tr><tr><td>UNKNOWN</td><td>Catch-all for unknown order state. Does not indicate a connectivity error; this state will only be observed in the case of unexpected API changes or in beta testing.</td></tr></tbody></table>


# Accounts and portfolio management

In the Architect PMS, portfolios are represented as accounts, which contain balances and positions. Accounts are mapped one-to-one with their correspondent on each venue, exchange, or clearing entity. All Architect-managed accounts are uniquely identified by UUID. The following are some examples of different kinds of accounts:

| Account                                 | Example accout name                           | Description                                                               |
| --------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------- |
| US futures and options clearing account | STONEX:ABC123/JohnDoe                         |                                                                           |
| US equities clearing account            | DORMAN:44444R/BLast                           |                                                                           |
| Coinbase portfolio                      | COINBASE:a2868946-2b80-4b9e-a672-cdda4bb200dc | For prop trading, the portfolio ID of a connected Coinbase crypto account |

### Balances and positions

Account balances describe the amount of cash or assets held; for example, an account may hold 5 BTC or 20 shares of AAPL, and have a margin balance of 1000 USD.&#x20;

Positions represent ownership or exposure to financial instruments in an account; for example, an account may be net short 10 shares of TSLA or net long 3 CME GC contracts. By default, positions are unaggregated and separate orders in the same instrument will result in distinct positions.


# Systems and connectivity diagram

* [Systems and connectivity diagram](#systems-and-connectivity-diagram)
  * [Brokerage topology](#brokerage-topology)
  * [Canonical endpoints](#canonical-endpoints)

## Brokerage topology

{% hint style="info" %}
Coming soon
{% endhint %}

## Canonical endpoints


# Authentication

Architect uses an OAuth provider to authenticate users on the platform. Users may create confidential API keys for programmatic access to Architect services. API keys must then be exchanged for short-lived JWTs, for direct connectivity to Architect for order entry and marketdata.

<figure><img src="/files/wozNpwvUGRWTQuC0b6er" alt=""><figcaption></figcaption></figure>


# Pagination


# Rate-Limiting

{% hint style="warning" %}
Effective December 19, 2025, Architect will enforce rate limits by user ID. The rate limits will impact any application, script, or manual usage that communicates excessively with the Architect API.

It is essential to review your code and the Architect documentation to ensure best practices in optimizing requests.
{% endhint %}

Architect limits the rate of incoming gRPC requests per user (including usage of the SDK) to ensure services are reliable and responsive. Rate limiting is enforced on a per-user basis, meaning each authenticated user has their own independent rate limit quota.

## Overview

Rate limiting applies to all gRPC requests made through the Architect API, including:

* Direct gRPC calls
* SDK usage (Python, TypeScript, Rust)
* Any application or script that communicates with Architect services

## How Rate Limiting Works

### Per-User Enforcement

Rate limits are enforced based on the authenticated user ID. When you make a request:

1. Architect extracts your user ID
2. The rate limiter checks your personal quota
3. If you have available tokens, the request proceeds
4. If your quota is exhausted, the request is rejected with a rate limit error

Note that multiple accounts under a single user share a single token bucket.

### Token Bucket Algorithm

The rate limiter uses a token bucket algorithm with the following characteristics:

* **Burst Capacity**: You can make a burst of requests up to your configured limit
* **Refill Rate**: Tokens are replenished over time according to your quota

For example, if your rate limit is 10 requests per second with a 100 burst capacity:

* You can make up to 100 requests immediately (burst)
* After consuming tokens, they refill at a rate of 10 per second
* If you exceed the burst capacity, you must wait for tokens to refill

## Default Rate Limits

By default the server will enforce rate limits with a **burst capacity** of 100 requests and a **refill rate** of 10 requests per second. This applies per user (not per account). However, Architect reserves the right to change these limits at any time depending on server capacity and use cases.

## Rate Limit Responses

When you exceed your rate limit, Architect returns a gRPC error with the following characteristics:

### Error Details

1. **gRPC Status Code**: `RESOURCE_EXHAUSTED` (code 8)
2. **Error Message**: `"rate limit exceeded"`
3. **Retry-After Header**: Provides the recommended wait time in milliseconds before retrying

### Handling the Error in Python Example

When using the Python SDK, you'll receive an `AioRpcError`:

**Example Error Output**:

```
AioRpcError: <AioRpcError of RPC that terminated with:
	status = StatusCode.RESOURCE_EXHAUSTED
	details = "rate limit exceeded"
	debug_error_string = "UNKNOWN:Error received from peer  {grpc_message:"rate limit exceeded", grpc_status:8}"
```

```python
from grpc import StatusCode
from grpc.aio import AioRpcError

try:
    # Some client request here
    for i in range(1000):
        _ = await client.list_accounts()
except AioRpcError as e:
    if e.code() == StatusCode.RESOURCE_EXHAUSTED:
        # Rate limit exceeded
        retry_after = e.trailing_metadata().get("retry-after")
        print(f"Rate limit exceeded: {e.details()}. Retry after {retry_after}")
    else:
        # Handle other errors
        raise
```

### Rust Example

When using the Rust SDK:

```rust
use tonic::{Code, Status};
use tokio::time::{sleep, Duration};
use humantime::parse_duration;

match client.list_accounts().await {
    Ok(response) => { /* Handle success */ }

    Err(status) if status.code() == Code::ResourceExhausted => {

        let duration = status.metadata()
            .get("retry-after")
            .and_then(|h| h.to_str().ok())
            .and_then(|s| humantime::parse_duration(s).ok())
            .unwrap_or(Duration::from_secs(1));

        eprintln!("Rate limit hit. Waiting {:?}...", duration);
        sleep(duration).await;
        // Place your retry logic here
    }
    Err(e) => {
        // Handle all other errors
        return Err(e);
    }
}
```

## Best Practices

### Use Streaming Channels Instead of Polling

The most effective way to stay within rate limits is to use Architect's streaming channels instead of repeatedly calling unary endpoints.

**Rate limit tokens are consumed per gRPC call, not per message on a stream.** Establishing a streaming connection like `orderflow` consumes only one token—all subsequent messages sent over that stream (PlaceOrder, CancelOrder, GetOrder, etc.) do not consume additional tokens.

| Approach                             | Rate Limit Impact                        |
| ------------------------------------ | ---------------------------------------- |
| Polling `get_order` in a loop        | 1 token per call ❌                       |
| Using `orderflow` channel            | 1 token to connect, unlimited messages ✅ |
| Subscribing to `subscribe_orderflow` | 1 token to connect, unlimited updates ✅  |

**Example: Prefer orderflow over polling**

```python

# Bad: Polling consumes rate limit tokens on every call
while True:
    order = await client.get_order('some_order')
    print(f" --> {order}")

# Good: Streaming uses only 1 token for the connection
async for event in client.stream_orderflow():
    print(f" --> {event}")
```

### Batch and Cache Where Possible

* **Batch requests**: Use batch endpoints (e.g., `place_batch_order`) instead of making multiple individual calls
* **Cache static data**: Cache infrequently changing data like account lists or product definitions to reduce redundant API calls

### Request Backoff

Clients should treat `RESOURCE_EXHAUSTED` as a signal to alleviate pressure. Retrying after a delay is recommended, and doubling the delay upon each consecutive `RESOURCE_EXHAUSTED` message is often best practice. You can apply some [jitter](https://en.wikipedia.org/wiki/Jitter) to avoid the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).

###

## FAQs

### What happens when I exceed the rate limit?

When you exceed your rate limit, your request is immediately rejected with a `RESOURCE_EXHAUSTED` error. Note that this differs from throttling (where requests are slowed down). Crucially, this means that rejected calls need to be resent (if still needed).

You must wait for tokens to refill before making additional requests. The error response includes a `Retry-After` header indicating how long you should wait.

### How do I know what my rate limit is?

Rate limit quotas are configured per deployment. Default rates will be posted, but contact the Architect team to learn the specific rate limits for your environment.

### Can I request a higher rate limit?

Rate limit quotas are configured based on system capacity and fair usage policies. Contact the Architect team to discuss your specific needs.

### Do rate limits apply to all gRPC methods?

Yes, rate limiting applies to all gRPC requests made to Architect services, regardless of the specific method or service being called.

### How are rate limits enforced across multiple connections?

Rate limits are enforced per user ID, not per connection. If you have multiple connections or clients using the same user credentials, they all share the same rate limit quota.


# Symbology and instrument info

* [Symbology](#symbology)
  * [List symbols](#list-symbols)
  * [Search symbols](#search-symbols)
  * [Get product info](#get-product-info)
  * [Get execution info](#get-execution-info)
  * [Get futures series](#get-futures-series)

## List symbols

List all symbols available on Architect, including both products and tradable product pairs (e.g. "AAPL US Equity" and "AAPL US Equity/USD" may both appear).

{% tabs %}
{% tab title="Python" %}

```python
symbols = await client.list_symbols()

for symbol in symbols:
    assert_type(symbol, str)
    print(symbol)
```

{% endtab %}
{% endtabs %}

## Search symbols

Search for tradable products on Architect using full text symbol search.

```python
from architect_py import TradableProduct

symbols = await client.search_symbols(
    search_string="BTC",
    execution_venue="BINANCE",
    offset=0,
    limit=20,
)

for symbol in symbols:
    assert_type(symbol, TradableProduct)
    print(symbol)  # e.g. "BTC Crypto/USDT Crypto"
```

## Get product info

Get information about a product, such as its type, underlying, multiplier, expiration, and other relevant fields.

{% tabs %}
{% tab title="Python" %}

```python
info = await client.get_product_info("ES 20250620 CME Future")

# get many product infos at once
infos = await client.get_product_infos([
    "ES 20250620 CME Future",
    "BTC Crypto",
])
```

{% endtab %}

{% tab title="Example JSON response" %}

```json
{
  "symbol": "ES 20250620 CME Future",
  "product_type": "Future",
  "multiplier": "50",
  "derivative_kind": "Linear",
  "primary_venue": "CME",
}
```

{% endtab %}
{% endtabs %}

## Get execution info

Get execution information for a tradable product, such as tick size, step size, margin requirements, and other relevant fields.

{% tabs %}
{% tab title="Python" %}

```python
info = await client.get_execution_info(
    "ES 20250620 CME Future/USD",  # tradable product
    "CME"                          # execution venue
)

# get many execution infos at once
infos = await client.get_execution_infos(
    [
        "ES 20250620 CME Future/USD",
        "BTC Crypto/USDT Crypto",
    ],
    "CME" 
)
```

{% endtab %}

{% tab title="Example JSON response" %}

```json
{
  "symbol": "ES 20250620 CME Future/USD",
  "execution_venue": "CME",
  "tick_size": "0.25",
  "step_size": "1",
  "min_order_quantity": "1",
  "is_delisted": false,
  "initial_margin": "24550",
  "maintenance_margin": "22318",
}
```

{% endtab %}
{% endtabs %}

## Get futures series

Get all futures in a given series.

{% tabs %}
{% tab title="Python" %}

```python
futures = await client.get_futures_series("ES CME Futures")
assert_type(futures, list[str])

assert futures == [
    'ES 20250321 CME Future',
    'ES 20250620 CME Future',
    'ES 20250919 CME Future',
    # ...
]
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::symbology::Product;

let futures: Vec<Product> = client.get_futures_series(
    "ES CME Futures",
    false,  // include_expired
).await?;
```

{% endtab %}
{% endtabs %}


# Marketdata

* [Marketdata](#marketdata)
  * [Get market status](#get-market-status)
  * [Get ticker](#get-ticker)
  * [Get L1 book snapshot](#get-l1-book-snapshot)
  * [Stream L1 book snapshots](#stream-l1-book-snapshots)
  * [Subscribe to L1 book](#subscribe-to-l1-book)
  * [Get L2 book snapshot](#get-l2-book-snapshot)
  * [Stream L2 book updates](#stream-l2-book-updates)
    * [Applying diffs](#applying-diffs)
    * [Sequence numbers](#sequence-numbers)
  * [Subscribe to L2 book](#subscribe-to-l2-book)
  * [Stream trades](#stream-trades)
  * [Stream candles (klines)](#stream-candles-klines)
    * [Streaming candles availability and request limits](#streaming-candles-availability-and-request-limits)
  * [Get historical candles](#get-historical-candles)
    * [Historical candles availability and request limits](#historical-candles-availability-and-request-limits)

## Get market status

Get the market status for a symbol and venue, e.g. if it's currently quoting or trading.

{% tabs %}
{% tab title="Python" %}

```python
status = await client.get_market_status(
    symbol="BTC Crypto/USD",
    venue="COINBASE"
)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::MarketStatus;

let status: MarketStatus = client.get_market_status("BTC Crypto/USD", "COINBASE").await?;
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  "s": "BTC Crypto/USD",  // symbol
  "is_quoting": true,
  "is_trading": true
}
```

{% endtab %}
{% endtabs %}

## Get ticker

Get a marketdata ticker for a symbol and venue. Tickers include basic summary statistics like volumes, open interest, settlement price, as well as slowly changing dimensions e.g. dividend yields, P/E ratios, market caps for equities.

{% tabs %}
{% tab title="Python" %}

```python
ticker = await client.get_ticker(
    symbol="AAPL US Equity/USD",
    venue="US-EQUITIES"
)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::Ticker;

let ticker: Ticker = client.get_ticker("AAPL US Equity/USD", "US-EQUITIES").await?;
```

{% endtab %}
{% endtabs %}

## Get L1 book snapshot

{% tabs %}
{% tab title="Python" %}

```python
snap = await client.get_l1_book_snapshot(
    symbol="GC 20250626 CME Future/USD",
    venue="CME"
)

# get multiple snapshots
snaps = await client.get_l1_book_snapshots(
    symbols=["GC 20250626 CME Future/USD", "ES 20250620 CME Future/USD"],
    venue="CME"
)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::L1BookSnapshot;

let snap: L1BookSnapshot = client.get_l1_book_snapshot(
    "GC 20250626 CME Future/USD",
    "CME"
).await?;

// get multiple snapshots
let snaps: Vec<L1BookSnapshot> = client.get_l1_book_snapshots(
    &[
        "GC 20250626 CME Future/USD",
        "ES 20250620 CME Future/USD"
    ],
    "CME"
).await?;
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  "s": "GC 20250626 CME Future/USD",  // symbol
  "tn": 710661000,                    // timestamp (seconds since epoch)
  "ts": 1747336563,                   // nanoseconds part of timestamp
  "a": ["3227.500000000", "3"],       // ask price and size
  "b": ["3227.200000000", "3"]        // bid price and size
}
```

{% endtab %}
{% endtabs %}

## Stream L1 book snapshots

Stream L1 book snapshots for the given symbols, for the given venue.

{% tabs %}
{% tab title="Python" %}

```python
async for snap in client.stream_l1_book_snapshots(
    symbols=["BTC Crypto/USD"], 
    venue="COINBASE"
):
    print(snap)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::L1BookSnapshot;
use futures::StreamExt;

let mut stream = client.stream_l1_book_snapshots(&["BTC Crypto/USD"], "COINBASE", false).await?;
while let Some(item) = stream.next().await {
    let snap: L1BookSnapshot = item?;
}
```

{% endtab %}
{% endtabs %}

## Subscribe to L1 book

Subscribe to the L1 book for a symbol and venue in a background task. The current state of the book is available anytime via the returned reference. Calling subscribe again for the same symbol and venue will return the same reference. Call the unsubscribe method to terminate the subscription.

{% tabs %}
{% tab title="Python" %}

```python
book = await client.subscribe_l1_book(
    symbol="BTC Crypto/USD",
    venue="COINBASE"
)

# ...
await client.unsubscribe_l1_book(
    symbol="BTC Crypto/USD",
    venue="COINBASE"
)
```

{% endtab %}
{% endtabs %}

## Get L2 book snapshot

{% tabs %}
{% tab title="Python" %}

```python
book = await client.get_l2_book_snapshot(
    symbol="GC 20250626 CME Future/USD",
    venue="CME"
)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::L2BookSnapshot;

let book: L2BookSnapshot = client.get_l2_book_snapshot("GC 20250626 CME Future/USD", "CME").await?;
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  "sid": 14673246569842529083,  // sequence id
  "sn": 3722556,                // sequence number
  "tn": 710661000,              // timestamp (seconds since epoch)
  "ts": 1747336563,             // nanoseconds part of timestamp
  "a": [                        // asks (price, size)
    ["3228.600000000", "2"],
    ["3228.700000000", "6"],
    ["3228.800000000", "6"],
    // ...
  ],
  "b": [                        // bids (price, size)
    ["3227.200000000", "3"],
    // ...
  ]
}
```

{% endtab %}
{% endtabs %}

## Stream L2 book updates

Stream L2 book updates for a given symbol and venue. This is a diff stream; the first message will contain a full snapshot, and subsequent messages represent diffs to be applied successively to maintain the state of the book.

{% tabs %}
{% tab title="Python" %}

```python
from architect_py import L2BookSnapshot, L2BookDiff

async for update in client.stream_l2_book_updates(
    symbol="BTC Crypto/USD",
    venue="COINBASE"
):
    if isinstance(update, L2BookSnapshot):
        print(update)
    elif isinstance(update, L2BookDiff):
        print(update)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::L2BookUpdate;
use futures::StreamExt;

let mut stream = client.stream_l2_book_updates("BTC Crypto/USD", "COINBASE").await?;

while let Some(item) = stream.next().await {
    let up = item?;
    match up {
        L2BookUpdate::Snapshot(snap) => {},
        L2BookUpdate::Diff(diff) => {}
    }
}
```

{% endtab %}
{% endtabs %}

### Applying diffs

For each diff message, a price level with non-zero quantity indicates that that price level should be updated to the stated quantity. A price level with a quantity of zero indicates that the price level should be removed from the book.

### Sequence numbers

Sequence numbers are monotonically increasing integers that are assigned to each message. They can be used to detect gaps in the stream. From the first snapshot, each diff message should have a sequence number that is exactly one greater than the sequence number of the last received update.

Additionally, messages include a sequence ID field. Sequence IDs must be the same for all updates in a stream; if the sequence ID is observed to change, diff updates are no longer valid and the subscription should be restarted with a new snapshot.

## Subscribe to L2 book

Subscribe to and maintain an L2 book for a given symbol and venue in a background task. The current state of the book is available anytime via the returned reference. Calling subscribe again for the same symbol and venue will return the same reference.

{% tabs %}
{% tab title="Python" %}

```python
book = await client.subscribe_l2_book(
    symbol="BTC Crypto/USD",
    venue="COINBASE"
)
```

{% endtab %}
{% endtabs %}

## Stream trades

Stream the latest trades for a given symbol and venue.

{% tabs %}
{% tab title="Python" %}

```python
async for trade in client.stream_trades(
    symbol="BTC Crypto/USD",
    venue="COINBASE"
):
    print(trade)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::Trade;
use futures::StreamExt;

let mut stream = client.stream_trades(Some("BTC Crypto/USD"), "CME").await?;

while let Some(item) = stream.next().await {
    let trade: Trade = item?;
}
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  "s": "BTC Crypto/USD",  // symbol
  "tn": 710661000,        // timestamp (seconds since epoch)
  "ts": 1747336563,       // nanoseconds part of timestamp
  "p": "3227.200000000",  // price
  "q": "3",               // size
  "d": "BUY"              // trade direction or side 
}
```

{% endtab %}
{% endtabs %}

## Stream candles (klines)

Candles are produced at different fixed periods and include the open, high, low, close, and volumes for that period. Not all exchange feeds produce all candle widths.

{% tabs %}
{% tab title="Python" %}

```python
from architect_py import CandleWidth

stream = client.stream_candles(
  symbol="BTC Crypto/USD", 
  venue="COINBASE",
  candle_widths=[CandleWidth.OneSecond]
)

async for candle in stream:
    print(candle)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::{Candle, CandleWidth};
use futures::StreamExt;

let mut stream = client.stream_candles(
    "BTC Crypto/USD",
    "COINBASE",
    Some(&[CandleWidth::OneSecond])
).await?;

while let Some(item) = stream.next().await {
    let candle: Candle = item?;
}
```

{% endtab %}
{% endtabs %}

### Streaming candles availability and request limits

<table><thead><tr><th width="154.92578125">Venue</th><th>Available candle widths for streaming</th></tr></thead><tbody><tr><td>CME</td><td>1s, 1h, 15m, 1h, 1d</td></tr><tr><td>CFE</td><td>1s, 1h, 15m, 1h, 1d</td></tr><tr><td>US-EQUITIES</td><td></td></tr></tbody></table>

## Get historical candles

Retrieve historical candles for a symbol and venue.

{% tabs %}
{% tab title="Python" %}

```python
from architect_py import CandleWidth
from datetime import datetime, timedelta, timezone

candles = await client.get_historical_candles(
    symbol="GC 20250428 CME Future/USD",
    venue="CME",
    candle_width=CandleWidth.OneHour,
    start=datetime.now(timezone.utc) - timedelta(days=1),
    end=datetime.now(timezone.utc)
    # pass as_dataframe=True to return a pandas DataFrame
)
```

{% endtab %}

{% tab title="Rust" %}

```rust
use architect_api::marketdata::{Candle, CandleWidth};
use chrono::{Utc, Duration};

let now = Utc::now();
let candles: Vec<Candle> = client.get_historical_candles(
    "GC 20250428 CME Future/USD",
    "CME",
    CandleWidth::OneHour,
    now - Duration::hours(12),
    now 
).await?;
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  "s": "GC 20250626 CME Future/USD", // symbol
  "w": 3600,                         // width
  "tn": 0,                           // timestamp (seconds since epoch)
  "ts": 1747292400,                  // nanoseconds part of timestamp
  "v": "14029",                      // volume
  "av": "6767",                      // ask volume
  "bv": "6748",                      // bid volume
  "o": "3153.500000000",             // open price
  "h": "3155.500000000",             // high price
  "l": "3134.200000000",             // low price
  "c": "3145.400000000",             // close price
  "ao": "3153.500000000",            // ask open price
  "ah": "3155.600000000",            // ask high price
  "al": "3134.300000000",            // ask low price
  "ac": "3145.400000000",            // ask close price
  "bo": "3153.200000000",            // bid open price
  "bh": "3155.400000000",            // bid high price
  "bl": "3134.000000000",            // bid low price
  "bc": "3145.100000000",            // bid close price
  "mo": "3153.3500000000",           // mid price
  "mh": "3155.5000000000",           // mid high price
  "ml": "3134.1500000000",           // mid low price
  "mc": "3145.2500000000",           // mid close price
}
```

{% endtab %}
{% endtabs %}

### Historical candles availability and request limits

<table><thead><tr><th width="119.26171875">Candle width</th><th>Maximum allowed start/end timespan in one request</th></tr></thead><tbody><tr><td>1s</td><td>8 hours</td></tr><tr><td>5s</td><td>1 day</td></tr><tr><td>1m</td><td>7 days</td></tr><tr><td>15m</td><td>90 days</td></tr><tr><td>1h</td><td>365 days (~1 year)</td></tr><tr><td>1d</td><td>3650 days (~10 years)</td></tr></tbody></table>

<table><thead><tr><th width="146.44921875">Venue</th><th>Earliest available data</th><th>Latest available data</th></tr></thead><tbody><tr><td>CME</td><td></td><td></td></tr><tr><td>CFE</td><td></td><td></td></tr><tr><td>US-EQUITIES</td><td></td><td></td></tr></tbody></table>


# Order entry

* [Order entry](#order-entry)
  * [Place limit order](#place-limit-order)
    * [Order request fields](#order-request-fields)
    * [Order types](#order-types)
    * [Time-in-force instructions](#time-in-force-instructions)
  * [Cancel order](#cancel-order)
  * [Cancel all orders](#cancel-all-orders)
  * [Batch cancel orders](#batch-cancel-orders)
  * [Reconcile out orders](#reconcile-out-orders)
  * [Orderflow channel](#orderflow-channel)
  * [Stream orderflow](#stream-orderflow)

## Place limit order

Place a limit order for a tradable product. If an execution venue isn't specified, the default venue for the symbol will be used. Depending on the time-in-force instruction, the order may require additional parameters.

{% tabs %}
{% tab title="Python" %}

```python
from decimal import Decimal
from architect_py import OrderDir

order = await client.place_limit_order(
    symbol="BTC Crypto/USD",
    execution_venue="COINBASE",
    account=None,                   # required for some venues
    dir=OrderDir.BUY,
    quantity=Decimal(1),
    limit_price=Decimal(10000),
    post_only=True,                 # optional
)

print(order.status)
```

{% endtab %}
{% endtabs %}

### Order request fields

<table><thead><tr><th width="166.6875">Field</th><th width="104.08984375">Required</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>N</td><td>Order ID to assign to the order; if not specified, the Architect OEMS will assign one randomly.</td></tr><tr><td>symbol</td><td>Y</td><td>Tradable product</td></tr><tr><td>dir</td><td>Y</td><td>Order side; BUY or SELL</td></tr><tr><td>quantity</td><td>Y</td><td>Order quantity</td></tr><tr><td>trader</td><td>N</td><td>Trader effecting the order; if not specified, Architect uses the logged-in user</td></tr><tr><td>account</td><td>N</td><td>Account for the order; if not specified, Architect will use the trader's default account configured for the execution venue.</td></tr><tr><td>order_type</td><td>Y</td><td>Order type</td></tr><tr><td>limit_price</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>post_only</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>trigger_price</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>time_in_force</td><td>Y</td><td>Order time-in-force instruction</td></tr><tr><td>execution_venue</td><td>N</td><td>Execution venue for the order; if not specified, Architect will use the primary venue for the symbol.</td></tr></tbody></table>

### Order types

<table><thead><tr><th width="205.31640625">Order type</th><th width="281.23046875">Description</th><th>Required fields</th></tr></thead><tbody><tr><td>LIMIT</td><td>Limit order; execute no worse than the limit price specified.</td><td><ul><li><strong>limit_price</strong></li><li><strong>post_only</strong>: only place the order if it would rest in the book; do not take</li></ul></td></tr><tr><td>STOP_LOSS_LIMIT</td><td>Stop-limit order; if the trigger price is breached, place a limit order at the price specified.</td><td><ul><li><strong>limit_price</strong></li><li><strong>trigger_price</strong></li></ul></td></tr><tr><td>TAKE_PROFIT_LIMIT</td><td>Take-profit order; if the trigger price is breached, place a limit order at the price specified. (Not implemented currently; please message if interested in using)</td><td><ul><li><strong>limit_price</strong></li><li><strong>trigger_price</strong></li></ul></td></tr><tr><td>MARKET</td><td>A market order.</td><td></td></tr></tbody></table>

### Time-in-force instructions

<table><thead><tr><th width="147.65234375">TIF instruction</th><th>Description</th></tr></thead><tbody><tr><td>GTC</td><td>Good-til-cancel</td></tr><tr><td>GTD</td><td>Good-til-date; datetime must be specified</td></tr><tr><td>DAY</td><td>Day order</td></tr><tr><td>IOC</td><td>Immediate-or-cancel</td></tr><tr><td>FOK</td><td>Fill-or-kill</td></tr><tr><td>ATO</td><td>At-the-open</td></tr><tr><td>ATC</td><td>At-the-close</td></tr></tbody></table>

## Place batch order

Place a batch order. Batch orders are multiple orders intended to be executed in a batch. The difference in placing a batch order instead of sending multiple place-orders depends on the specific venue. Some venues have optimized batch order placement APIs or atomicity guarantees that would differentiate it from vanilla multiple orders.

{% tabs %}
{% tab title="Python" %}

```python
from decimal import Decimal
from architect_py import OrderDir
from architect_py.batch_place_order import BatchPlaceOrder

batch = BatchPlaceOrder()

# call `place_order` for each order in the batch;
# orders are added to the batch but not yet submitted
await batch.place_order(
    symbol="BTC Crypto/USD",
    execution_venue="COINBASE",
    account=None,                   
    dir=OrderDir.BUY,
    quantity=Decimal(1),
    limit_price=Decimal(10000),
    post_only=True,                 
)

# send batch order to OMS
await client.place_batch_order(batch)
```

{% endtab %}
{% endtabs %}

## Cancel order

Request to cancel an order by order ID. Cancel requests are asynchronous and return immediately. The order is canceled when the exchange confirms the cancellation.

{% hint style="warning" %}
A working order is only canceled when the exchange confirms the cancellation, which can be checked by polling the order status.
{% endhint %}

{% tabs %}
{% tab title="Python" %}

```python
cancel = await client.cancel_order("12345678-1234-5678-1234-567812345678:0")  

print(cancel.status)
```

{% endtab %}
{% endtabs %}

## Cancel all orders

Request to cancel all orders matching the selectors.

{% tabs %}
{% tab title="Python" %}

```python
await client.cancel_all_orders(execution_venue="CME")
```

{% endtab %}
{% endtabs %}

## Batch cancel orders

Cancel multiple order IDs in one batch. This may or may not have different semantics from individually canceling each order, depending on the venue. Order IDs to be canceled will be batched by their execution venues.

{% tabs %}
{% tab title="Python" %}

```python
await client.batch_cancel_orders(order_ids=[])
```

{% endtab %}
{% endtabs %}

## Reconcile out orders

In cases where the state of an order falls out of sync, e.g. Architect thinks an order is still open but the order is known to be out/canceled by a human, use this manual reconciliation endpoint to force the order out. This is particular common in the case of staled orders.

{% tabs %}
{% tab title="Python" %}

```python
await client.reconcile_out(order_id="a0bcb1f4-4f9d-45c1-8bad-6d1239f0a2e2:0")

# or, reconcile out multiple orders
await client.reconcile_out(order_ids=[])
```

{% endtab %}
{% endtabs %}

## Orderflow channel

The most efficient way to trade using the Architect OEMS is to use the bidirectional orderflow channel. This is similar to a websocket or FIX session where one connection is opened and maintained for an entire trading session. The client will send place order and cancel order requests and receive order status updates and fills in realtime.

The specific mechanics of using the orderflow channel depend on the specific language SDK's implementation.

{% tabs %}
{% tab title="Python" %}
{% hint style="info" %}
Example coming soon
{% endhint %}
{% endtab %}
{% endtabs %}

## Stream orderflow

Subscribe to orderflow events, order status updates, fills from the Architect OEMS. The events streamed are the same as those received by the `orderflow` bidirectional channel.

{% tabs %}
{% tab title="Python" %}
{% hint style="info" %}
See [examples/orderflow\_streaming.py](https://github.com/architect-xyz/architect-py/blob/main/examples/orderflow_streaming.py) for a more comprehensive example.
{% endhint %}

```python
async for event in client.stream_orderflow():
    print(event)
```

{% endtab %}
{% endtabs %}

## Get open orders

Get all open orders matching the selectors.

{% tabs %}
{% tab title="Python" %}

```python
orders = await client.get_open_orders()

for order in orders:
    print(order.id)
```

{% endtab %}
{% endtabs %}

## Get historical orders

Get all historical orders (orders whose statuses are not `PENDING` nor `OPEN`) matching the selectors. If `order_ids` is not specified, then `from_inclusive` and `to_exclusive` are required.

{% tabs %}
{% tab title="Python" %}

```python
orders = await client.get_historical_orders()

for order in orders:
    print(order.id)
```

{% endtab %}
{% endtabs %}

## Get fills

Get all fills matching the selectors.

{% tabs %}
{% tab title="Python" %}

```python
res = await client.get_fills()

for fill in res.fills:
    print(fill.id)
```

{% endtab %}
{% endtabs %}

### Fill IDs

Architect attempts to uniquely identify fills, executions, or trades across all venues. They are typically UUIDv5s which are derived from exchange fill IDs and other characteristics of the fill necessary to make the identifications unambiguous.


# Portfolio management

* [Portfolio management](#portfolio-management)
  * [List accounts](#list-accounts)
    * [Account permissions](#account-permissions)
  * [Get account summary](#get-account-summary)
    * [Account summary fields](#account-summary-fields)
  * [Get account history](#get-account-history)
  * [Paper Trading Accounts](#paper-trading-accounts)
    * [Enable paper trading (GraphQL)](#enable-paper-trading-graphql)
    * [Open paper account](#open-paper-account)
    * [Reset paper account](#reset-paper-account)

## List accounts

List all accounts available to the user. This includes FCM accounts, which must be specified when sending orders.

{% tabs %}
{% tab title="Python" %}

```python
res = await client.list_accounts()

for item in res:
    print(item.account.name)
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
[
  {
    account: {
      id: "00000000-0000-0000-0000-000000000000",
      name: "STONEX:000000/JDoe",
    },
    permissions: {
      list: true,
      reduce_or_close: true,
      set_limits: true,
      trade: true,
      view: true,
    },
    trader: "00000000-0000-0000-0000-000000000000",
  },
  {
    account: {
      id: "00000000-0000-0000-0000-000000000001",
      name: "STONEX:000001/JDoe",
    },
    permissions: {
      list: true,
      reduce_or_close: true,
      set_limits: true,
      trade: true,
      view: true,
    },
    trader: "00000000-0000-0000-0000-000000000000",
  },
]
```

{% endtab %}
{% endtabs %}

### Account permissions

<table><thead><tr><th width="193.8046875">Permission</th><th>Description</th></tr></thead><tbody><tr><td>list</td><td>Trader is allowed to know about the account but not its balances or positions</td></tr><tr><td>reduce_or_close</td><td>Trader can send orders only to reduce or close (risk manager)</td></tr><tr><td>set_limits</td><td>Trader allowed to set or change risk limits on the account</td></tr><tr><td>trade</td><td>Trader allowed to send orders</td></tr><tr><td>view</td><td>Read-only view of account, including balances and positions</td></tr></tbody></table>

## Get account summary

Get an account summary for a specified account.

{% tabs %}
{% tab title="Python" %}

```python
res = await client.get_account_summary("STONEX:000000/JDoe")
print(res)

# get multiple account summaries
res = await client.get_account_summaries([
    "STONEX:000000/JDoe",
    "STONEX:000001/JDoe"
])
print(res)
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  account: "00000000-0000-0000-0000-000000000000",
  balances: {
    USD: "5754.59",
  },
  positions: {
    "MGC 20250626 CME Future/USD": [
      {
        quantity: "1",
        cost_basis: "3279.2",
      },
    ],
  },
  timestamp: "2025-05-15T22:32:21.222906Z",
  cash_excess: "0",
  position_margin: "1650",
  purchasing_power: "5447.59",
  realized_pnl: "0",
  total_margin: "1650",
  unrealized_pnl: "0",
}
```

{% endtab %}
{% endtabs %}

### Account summary fields

<table><thead><tr><th width="221.86328125">Field</th><th>Description</th></tr></thead><tbody><tr><td>account</td><td>Account ID</td></tr><tr><td>timestamp</td><td>Snapshot timestamp</td></tr><tr><td>equity</td><td>Total account equity or net liquidation value</td></tr><tr><td>cash_excess</td><td>Withdrawable cash</td></tr><tr><td>purchasing_power</td><td>Total purchasing power of the account</td></tr><tr><td>unrealized_pnl</td><td>Unrealized P&#x26;L</td></tr><tr><td>realized_pnl</td><td>Realized P&#x26;L</td></tr><tr><td>yesterday_equity</td><td>Yesterday account equity or net liquidation value; not provided on all venues</td></tr><tr><td>total_margin</td><td>Margin usage including open orders and positions</td></tr><tr><td>position_margin</td><td>Margin usage including only positions</td></tr><tr><td>balances</td><td>Map of products/assets to their quantities</td></tr><tr><td>positions</td><td>See "Account Positions" table</td></tr></tbody></table>

## Get position summary

Get an aggregated summary of positions and a snapshot of unrealized PnL and notional value for a specified account(s).

{% tabs %}
{% tab title="Python" %}

```python
# defaults to all accounts
res = await client.get_positions_summary()
print(res)
```

{% endtab %}

{% tab title="Example JSON response" %}

```json5
{
  direction: "BUY",
  quantity: "10",
  symbol: "NQ 20251219 CME Future/USD",
  avg_cost_basis: "25730",
  current_price: "25706.75",
  notional_usd: "5141350",
  unrealized_pnl: "-4650",
}
```

{% endtab %}
{% endtabs %}

## Get account history

Get historical snapshots of account summaries for the specified account.

{% tabs %}
{% tab title="Python" %}

```python
from datetime import datetime

res = await client.get_account_history(
    account="STONEX:000000/JDoe",
    from_inclusive=datetime(2025, 1, 1),
    to_exclusive=datetime(2025, 1, 2)
)
print(res)
```

{% endtab %}
{% endtabs %}

## Paper Trading Accounts

Paper trading accounts allow users to test strategies and practice trading without real money. Each user automatically has access to a default paper account with the format `PAPER:{email}`. Users can create up to 2 additional paper accounts.

### Enable paper trading (GraphQL)

Enable paper trading for the authenticated user through the GraphQL API. This creates the default paper account if it doesn't exist.

{% tabs %}
{% tab title="GraphQL" %}

```graphql
mutation {
  user {
    enablePaperTrading
  }
}
```

{% endtab %}

{% tab title="Example Response" %}

```json
{
  "data": {
    "user": {
      "enablePaperTrading": true
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Open paper account

Create a new paper trading account for the authenticated user.

**Request Parameters:**

* `account_name` (optional): Custom name for the paper account
  * If not specified, creates/accesses the default account `PAPER:{email}`
  * When specified, creates account as `PAPER:{email}:{account_name}`
* `usd_balance_cents` (optional): Initial balance in USD cents
  * If not specified, uses default balance ($100,000)

{% tabs %}
{% tab title="Python" %}

```python
# Create default paper account
res = await client.open_paper_account()
print(f"Account: {res.account.name}")
print(f"Account ID: {res.account.id}")

# Create named account with custom balance
res = await client.open_paper_account(
    account_name="my_strategy_test",
    usd_balance_cents=500000  # $5,000.00
)
print(f"Account: {res.account.name}")
```

{% endtab %}

{% tab title="Example Response" %}

```json
{
  "account": {
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "PAPER:user@example.com:my_strategy_test"
  }
}
```

{% endtab %}
{% endtabs %}

**Note:** Users can have 1 default account plus up to 2 additional named accounts. Contact Architect for access to additional accounts.

### Reset paper account

Reset the cash balance in a paper account.

**Request Parameters:**

* `account`: Account identifier (UUID or name)
  * Accepts: `PAPER:{email}`, `PAPER:{email}:{name}`, or account UUID
* `usd_balance_cents` (optional): Balance to reset to in USD cents
  * If not specified, resets to default balance

{% tabs %}
{% tab title="Python" %}

```python
# Reset account to default balance
res = await client.reset_paper_account("PAPER:user@example.com")

# Reset account with a specific balance
res = await client.reset_paper_account(
    account="PAPER:user@example.com:my_strategy_test",
    usd_balance_cents=100000  # $1,000.00
)

# Reset using account UUID
res = await client.reset_paper_account(
    account="00000000-0000-0000-0000-000000000000",
    usd_balance_cents=500000  # $5,000.00
)
```

{% endtab %}

{% tab title="Example Response" %}

```json
{
  // Empty response indicates success
}
```

{% endtab %}
{% endtabs %}

### Error Handling

Common error scenarios and solutions:

**Account Limit Exceeded**

* Error when trying to create more than three paper accounts
* Solution: Contact Architect for increased limits, support\[at]architect.co

**Account Not Found**

* Specified account doesn't exist for reset operations
* Verify account name/ID is correct
* Ensure account was created before attempting operations


# Connection management

* [Get cpty status](#get-cpty-status)

## Get cpty status

Get the status of a cpty connection.

{% tabs %}
{% tab title="Python" %}

```python
status = await client.cpty_status(kind="binance")
```

{% endtab %}
{% endtabs %}

Returned fields:

* `connected`: true iff all component connections are connected, e.g. sockets are connected
* `stale`: true iff any component connection is stale, e.g. missed a protocol heartbeat
* `logged_in`: true iff all component connections are logged in (if relevant)
* `connections`: map of individual connections statuses relevant to the cpty
* `connections.connected`: connection is physically established, e.g. socket is connected
* `connections.last_heartbeat`: UNIX timestamp (seconds) of last heartbeat from connection, or `-1` for never
* `connections.last_heartbeat_stale_threshold`: threshold in seconds for considering a connection stale, e.g. if a heartbeat is missed
* `connections.logged_in`: true if connection is logged in, or `null` if not relevant


# Overview

Architect provides a suite of order execution algos out-of-the box. These algorithms wrap common order execution strategies into abstracted order types that you can configure and operate with ease.

{% hint style="warning" %}
Generally, users should never manually cancel individual orders sent by an algo. If you want to cancel the individual order, the user is expected to stop the entire algo.
{% endhint %}

{% tabs %}
{% tab title="Python" %}

```python
# params defined according to which algo you want to use. 
# Then all that's left is to call:
order = await client.place_algo_order(params=params, account=account)

# you can monitor it later with:
status = await client.get_algo_order_status(order.id)

# or view historical algo orders
historical_orders = await client.get_historical_algo_orders(order.id)

# modify the order if necessary
new_order = await client.modify_algo_order(algo_order_id=order.id, params=params)

# or just stop it
stop_respose = await client.stop_algo_order(order.id)
```

{% endtab %}
{% endtabs %}


# QuoteOneSide

An algorithm that quotes one side of a market by joining the passive side within a specified number of ticks, with the option to improve the market by one tick to gain queue priority.

The algo is similar to a limit order on the surface, but provides additional execution functionality in a couple of critical ways:&#x20;

* This algo will always put out a limit order with a price that is equal to or less aggressive than the set `limit price`&#x20;
* However, it will attempt to only post liquidity, so it will not cross the market unless the market moves toward the order while the order is in flight. In the `JOIN` mode, it joins the best bid (when buying) or offer (when selling)
* It can be parameterized with the `IMPROVE` mode to improve the market by one tick to gain queue priority, as long as the price is less aggressive than the `limit price`

The algorithm continuously monitors the market and repositions the quote as needed to maintain\
competitiveness while respecting the specified constraints. It will have at most one order at a time out in the market.&#x20;

### Use Cases

* While executing passively, to get filled at favorable prices without crossing the market
* While spread trading, to quote the passive side of a spread while maintaining price competitiveness
* While market making, to provide liquidity to one side of the market

### QuoteOneSideParams

| Parameter                           | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| dir *(OrderDir)*                    | Designate your order as buy or sell with the binary enums `OrderDir.BUY` or `OrderDir.SELL`                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| quantity *(decimal)*                | The quantity to execute. The algorithm terminates when filled to the nearest lot less than or equal to quantity                                                                                                                                                                                                                                                                                                                                                                                                                       |
| limit\_price *(decimal)*            | The most aggressive price the algo will quote at                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| max\_ticks\_outside  *(decimal)*    | <p>Maximum number of ticks less aggressive than the BBO to quote </p><ul><li> <code>None</code>: No constraint on distance from BBO — will quote at any valid price up to the limit price</li><li> <code>n</code>: Will only quote if within n ticks of the best same-side price (BBO) </li></ul><p>Orders beyond this distance are cancelled as they're unlikely to fill</p><ul><li>Example: With <code>5</code> for a buy order, if best bid is 100, will only quote between 95-100</li></ul><p>This must be a positive integer</p> |
| improve\_or\_join *(ImproveOrJoin)* | Designate whether to improve the market or join at the current best price with the binary enums `ImproveOrJoin.Join` or `ImproveOrJoin.Improve`                                                                                                                                                                                                                                                                                                                                                                                       |
| quantity\_filled *(decimal)*        | This is used to synchronize and track fill quantities when modifying the QuoteOneSide algo. Set it to 0 if initiating a new algo order                                                                                                                                                                                                                                                                                                                                                                                                |
| symbol *(str)*                      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| marketdata\_venue *(str)*           |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| exchange\_venue *(str)*             |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| account *(str, optional)*           |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |

### QuoteOneSideStatus

| Field                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| front\_of\_queue      | <p>Indicates whether the current quote is at the front of the queue (best price on our side). Being front of queue provides priority for fills.</p><ul><li>For Buy orders: <code>true</code> when our quote price > previous best bid on the market </li><li>For Sell orders: <code>true</code> when our quote price < previous best ask on the market </li><li>Also <code>true</code> when we're the first to establish a quote on our side (no existing bid/ask) </li></ul><p>This status updates dynamically as market conditions change and other orders arrive/cancel </p> |
| is\_cancelling        | Indicates whether the algorithm is currently cancelling an order                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| orders\_sent          | Number of orders sent by the algo                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| quantity\_filled      | Quantity filled by the algo                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| current\_quote\_price | The active quote price                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| realized\_avg\_price  | The average filled price of the algo                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |

### Example

{% tabs %}
{% tab title="Python" %}

```python
from architect_py import QuoteOneSideParams, ImproveOrJoin, OrderDir

symbol = "NQ 20251219 CME Future"
tp = f"{symbol}/USD"
venue = "CME"
account="PAPER:example@email.com"
params = QuoteOneSideParams.new(
    dir=OrderDir.BUY,
    execution_venue=venue,
    marketdata_venue=venue,
    quantity_filled=0,
    improve_or_join=ImproveOrJoin.Join,
    limit_price = 26000,
    quantity=1,
    symbol=tp,
)
order = await client.place_algo_order(params=params, account=account)
```

{% endtab %}
{% endtabs %}

### API Reference

{% embed url="<https://docs.rs/architect-api/latest/architect_api/algo/quote_one_side/struct.QuoteOneSideParams.html>" %}


# Spreader

An advanced algo for trading spreads between products in different order books.

Configure the spreader to trade a designated **spread** between multiple products. You define the parameters for each leg of the spread, and some general spread settings to match your desired execution preferences.&#x20;

The spreader can be used for a variety of different strategies, including cross-exchange arbitrage, futures vs spot basis trading, and relative value trading. Common examples of spreads are ES-SPY, HO-G, BTC Fut - BTC Perp, BTC Perp - BTC Spot.&#x20;

{% hint style="info" %}
Currently, the spreader supports two-leg spread configurations. Support for n-leg spreads is planned for a future release.
{% endhint %}

The spreader works through 2 execution styles:

1. **Spread Taking**
   1. No orders out until the spread hits the desired level
   2. The algo will then send orders out relative to the **far side** (the crossing side) of the BBO
2. **Quote then Hedge**
   1. Each product can quote relative to the **near side** of the BBO. If it gets filled, all other legs will fire a taking order at the far side of their order books. Therefore, the price of each quote is based on the required price to get the desired spread value assuming that all the other legs are takes

<figure><img src="/files/qWs2Kfe2o8ShsKqI93nD" alt=""><figcaption><p>Figure 1: Execution for a spread that trades with <a href="/pages/6waksW4JsB0vJK5dSxVh">price multipliers</a> of 1 and -1 respectively. Note that the same execution holds true for market 2 (in particular, the labelling of market 1 and 2 is completely arbitrary)</p></figcaption></figure>

A spread will have **legs** with **quoting** parameters that you [configure](/algos-book/spreader/leg-configuration). **Taking** parameters apply at the [spread level](/algos-book/spreader/spread-level-configuration). The **taking** **params** will be relative to the far side of the bbo. The **quoting params** will be relative to the near sid&#x65;**.**

{% hint style="info" %}
Every leg will have *at most* one taking order, one quoting order, and one quote hedge out at once.
{% endhint %}

### Setting the Limit Price

The [`limit_price` ](/algos-book/spreader/spread-level-configuration)is similar to the price of a limit order in the synthetic spread orderbook. It is the most aggressive (i.e. worse price you are willing to accept) level you are looking for the algo to trade the spread. This parameter will determine how the algo quotes and takes in each leg.

For example, in *Figure 1* if the `limit_price` is -0.06 we will quote in market 2, assuming we can hedge aggressively into the bid in market 1. However, we will not quote in market 1, because if we do get filled, we cannot hedge immediately at the best bid of 100.5 in market 2 without violating our `limit_price` of -0.06 (assuming we get the fill, it would come to a spread price of -0.05). We will also not submit any simultaneous **spread taking** orders, as these will grab us fills with an aggregate spread price at -0.04.

In real markets, While the spreader's quotes and spread takes in each leg are priced with prospective fills in other legs in mind, these orders might not get filled if the market moves away from you in market B right after a fill in market A, leaving you "hung".

[`chase_ticks`](/algos-book/spreader/leg-configuration) is designed to reduce the probability of getting "hung" on one leg as the other moves away from you, by designating a certain amount of ticks you are willing to pay up by on that leg. While this greatly alleviates the fill probability issue and is generally recommended for securing hedges, it introduces **slippage**. Slippage, particularly in the leg that is hedging or taking, is the difference between the expected execution price and the price of the fill. With slippage it is possible for the spreader algo to get prices worse than the designated `limit_price`. Therefore, the `chase_ticks` parameter should be configured cleverly by the user to strike a balance between higher hedge fill probability and lower slippage.

{% embed url="<https://docs.rs/architect-api/latest/architect_api/algo/spreader/struct.SpreaderParams.html>" %}


# Leg Configuration

The configuration for each leg defines the spread as a whole. They also allow customization of each leg's individual execution behavior

Spreads are defined by a weighted sum of the individual leg's prices, using `price_multiplier`, with an optional `price_offset`.&#x20;

$$
SpreadPrice =\sum\_{i=1}^n PriceMultiplier\_i \* (Price\_i + PriceOffset)
$$

The `quantity_ratio` actually determines the ratio of contracts quantities you are trading in each leg. Most of the time, the `quantity_ratio` should be equal to `price_multiplier`. However, there are some instances where you may want the `quantity_ratio` to differ, such as when there are contract point values at play. For example, imagine a [ES](https://www.cmegroup.com/markets/equities/sp/e-mini-sandp500.contractSpecs.html) - [MES](https://www.cmegroup.com/markets/equities/sp/micro-e-mini-sandp-500.contractSpecs.html) spread. While you may wish to price it as long 1 ES, short 1 MES (`price_multiplier` of 1 and -1, respectively), ES has a contract point value of $50, whereas MES has one of $5. This means that to actually achieve the correct *notional* exposure that matches your long 1 ES, short 1 MES spread price, you would need to use a `quantity_ratio` of 1 and -10. Any multiple of this ratio, such as 0.1 and -1 works the same.

For another example, take [Heating-Oil (HO)](https://www.cmegroup.com/markets/energy/refined-products/heating-oil.html) vs [Gasoil (G)](https://www.ice.com/products/34361119/low-sulphur-gasoil-futures):\
\- HO is priced in $ / per gallon, G is priced in $ / metric ton\
\- HO contract size is 42,000 gallons, G contract size is 100 metric tons

If we want to standardize the units of these two contracts and trade the resulting spread, we could set:\
\- 1 gallon of heating oil is around 0.00318 metric tons, so the `price_multiplier` would be `1 HO x -0.00318 G`\
\- 42,000 gallons of heating oil is around 133.56 metric tons, so a `quantity_ratio` of `3 HO x -4 G` would yield a similar tonnage (\~400 vs 400 metric tons)

{% hint style="info" %}
The sign of your `price_multiplier` for each leg **must match** that of your `quantity_ratio` , as the algo needs to take into account the buy/sell direction of your order to price using the corresponding bid/ask.
{% endhint %}

{% hint style="info" %}
Fractional units can be given, but quantities will be rounded down if they cannot be rounded to a whole lot.&#x20;
{% endhint %}

### LegParams

| Parameter                                           | Description                                                                                                                                                                                                                                                                                                                                     |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| price\_multiplier *(decimal)*                       | The weight to assign to this leg for spread pricing                                                                                                                                                                                                                                                                                             |
| quantity\_ratio *(decimal)*                         | The quantity ratio of contracts to trade this leg with respect to a spread unit. Note that when a spread quote or take order hits the market, quantity\_ratio determines your legs' relative order sizing, not the price\_multiplier, as the latter is only used for the spread pricing                                                         |
| price\_offset *(decimal)*                           | The offset to apply to this leg *before* weighing it with price\_multiplier. This might be used if there is some bias, costs or other adjustment you wish to make to this leg's price before computing the overall spread price                                                                                                                 |
| chase\_ticks *(unsigned integer)*                   | The number of ticks more aggressive than the desired price for a taking order. Using chase\_ticks > 0 decreases your changes of "getting hung", or remaining unhedged relative to the spread, after another leg gets a fill. However, when chase\_ticks > 0, it is possible to get filled at a spread price that is worse than your limit price |
| quoting\_parameters *(QuotingParameters, optional)* | Specify optional quoting parameters (see below). If not specified or left as None, this leg will **not quote**                                                                                                                                                                                                                                  |
| symbol *(str)*                                      |                                                                                                                                                                                                                                                                                                                                                 |
| marketdata\_venue *(str)*                           |                                                                                                                                                                                                                                                                                                                                                 |
| execution\_venue *(str)*                            |                                                                                                                                                                                                                                                                                                                                                 |
| account *(str)*                                     |                                                                                                                                                                                                                                                                                                                                                 |

### QuotingParameters

Under the hood, Spreader utilizes the [QuoteOneSide](/algos-book/quoteoneside) algo for smart quoting behavior, if the `quoting_parameters` field is specified.&#x20;

| Parameter                                  | Description                                                                                                                                                                                                      |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| max\_quote\_quantity *(decimal, optional)* | Maximum quantity to quote at a time for this leg. If left as None, the quantity quoted will be the minimum of the posted liquidity on the **other leg,** or the remaining quantity to satisfy the spreader order |

{% embed url="<https://docs.rs/architect-api/latest/architect_api/algo/spreader/struct.SpreaderParams.html>" %}


# Spread Level Configuration

Spread level parameters define the general execution configuration. See the Leg Configuration to parametrize each leg individually

| Parameter                                   | Description                                                                                                                                                                               |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| dir *(OrderDir)*                            | Designate your order as buy or sell with the binary enums `OrderDir.BUY` or `OrderDir.SELL`                                                                                               |
| quantity *(decimal)*                        | The quantity to execute. The algorithm terminates when each leg `i` is filled to the nearest lot less than or equal to `quantity * quantity_ratio[i]`                                     |
| limit\_price *(decimal)*                    | The most aggressive price the spread will take or quote at defined as a spread price.                                                                                                     |
| leg1 *(LegParams)*                          | See [Leg Configuration](/algos-book/spreader/leg-configuration)                                                                                                                           |
| leg2 *(LegParams)*                          | See [Leg Configuration](/algos-book/spreader/leg-configuration)                                                                                                                           |
| taking\_parameters *(TakingParameters)*     | See [TakingParameters](#takingparameters)                                                                                                                                                 |
| missed\_hedge\_policy *(MissedTakePolicy)*  | Specify how you want to deal with missed hedges or takes on one leg. Either **MissedTakePolicy.Halt** to pause the autospreader, or **MissedTakePolicy.Continue** to  ignore and continue |
| missed\_hedge\_wait\_time *(HumanDuration)* | Specify a certain amount of time an unfilled hedge waits before your configured **MissedTakePolicy** triggers                                                                             |

### TakingParameters

| Parameter                                      | Description                                                                                                                                                                                                                                           |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| min\_quantity\_threshold *(decimal, optional)* | Minimum quantity needed on the spread quantity for the spread before firing. However, if the remaining spread quantity is below this threshold, the `min_quantity_threshold` will be ignored so that the spread can submit the remainder of its order |
| max\_fire\_quantity *(decimal, optional)*      | Maximum fire/take quantity at once                                                                                                                                                                                                                    |
| take\_lockout *(HumanDuration)*                | Specify a certain amount of time before another spread-taking order can fire again                                                                                                                                                                    |

{% tabs %}
{% tab title="Python" %}

```python
from architect_py import (
    SpreaderParams,
    LegParams,
    QuotingParameters,
    TakingParameters,
    MissedTakePolicy,
    OrderDir,
    HumanDuration,
)
 
symbol1 = 'NQ 20251219 CME Future' 
symbol2 = 'MNQ 20251219 CME Future'
tp1 = f"{symbol1}/USD"
tp2 = f"{symbol2}/USD"
account = "PAPER:example@email.com"
venue = "CME"
params = SpreaderParams.new(
    dir=OrderDir.BUY,
    quantity=100,
    limit_price=10,
    leg1=LegParams.new(
        symbol=tp1,
        marketdata_venue=venue,
        execution_venue=venue,
        quantity_ratio=1,
        price_multiplier=1,
        price_offset=0,
        chase_ticks=0,
        quoting_parameters=QuotingParameters.new(max_quote_quantity=2),
    ),
    leg2=LegParams.new(
        symbol=tp2,
        marketdata_venue=venue,
        execution_venue=venue,
        quantity_ratio=-10,
        price_multiplier=-1,
        price_offset=0,
        chase_ticks=0,
        quoting_parameters=QuotingParameters.new(max_quote_quantity=20),
    ),
    taking_parameters=TakingParameters.new(
        min_quantity_threshold=None,
        max_fire_quantity=None,
        take_lockout=None,
    ),
    missed_hedge_policy=MissedTakePolicy.Halt,
    missed_hedge_wait_time=HumanDuration('30s'),
)

order = await client.place_algo_order(params=params, account=account)
```

{% endtab %}
{% endtabs %}


# Spreader Status

### SpreaderStatus

| Parameter                | Description                                                                                           |
| ------------------------ | ----------------------------------------------------------------------------------------------------- |
| leg1\_fill\_quantity     | Signed, filled quantity on leg 1                                                                      |
| leg2\_fill\_quantity     | Signed, filled quantity on leg 2                                                                      |
| implied\_spread\_vwap    | The average filled price of completed spread units so far                                             |
| current\_spreader\_phase | [SpreaderPhase](#spreaderphase)                                                                       |
| leg1\_quote\_order\_id   | The [QuoteOneSide](/algos-book/quoteoneside) order ID for Leg1, if Leg1 has a quote out in the market |
| leg2\_quote\_order\_id   | The [QuoteOneSide](/algos-book/quoteoneside) order ID for Leg1, if Leg1 has a quote out in the market |
| spread\_price            | The current spread taking price (the price to cross the implied market)                               |

### SpreaderPhase

| Parameter              | Description                                                                                                                                                                   |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **NoBbo**              | Either the bid or the ask does not exist. Usually this means the market is closed, or you caught the algo before it fully subscribed to market data (common in paper trading) |
| **Waiting**            | Algo order is live, but no orders in any of the legs are in the market                                                                                                        |
| **OrdersInMarket**     | Algo order is live, with orders in at least one of the legs live in the market                                                                                                |
| **DoneNotFullyFilled** | Algo order has halted (generally from **MissedTakePolicy.Halt**) but the original spreader quantity is not fully complete                                                     |
| **Done**               | Algo order has completed                                                                                                                                                      |


# TWAP

The Time-Weighted Average Price (TWAP) algo attempts to spread out an order evenly throughout a period of time. Using a TWAP execution is one way to achieve an average price that matches the market and can help minimize slippage and reduce costs.&#x20;

<br>

<figure><img src="/files/3sYAJYayCI35h5qKkDjP" alt=""><figcaption><p>In this TWAP example, the algo will buy 10 Bitcoin (BTC) for USD on Coinbase between now and 04/01/2024 14:37 PM (that is, 1 hour from now). To execute, the algo will send orders every 15 seconds at a price that is 10bp above the BTC/USD offer on Coinbase. The algo estimates a total cost of ~$656k USD, and each individual child order will be ~0.042 BTC in size. </p></figcaption></figure>

We can choose the parameters based on the trading goals.&#x20;

<table><thead><tr><th width="213">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>Buy/Sell</td><td>Direction of the order</td></tr><tr><td>Market</td><td>Symbol &#x26; price currency of the market, and the exchange</td></tr><tr><td>Quantity</td><td>Total quantity that will execute, measured in token units or contracts</td></tr><tr><td>Time Interval</td><td>Amount of time to wait between orders</td></tr><tr><td>Take Through Fraction</td><td>At what price to send the order, relative to the opposite side market.  For example on a buy order, a take through fraction of 0 would send bids at a price equal to the best offer at the time, and a take through fraction of 0.0005 would send bids 0.05% (5 basis points) above the current offer. Increasing this parameter above 0 reduces the chance of missing out on trades in a fast moving market, but has a higher risk of price slippage. </td></tr><tr><td>Reject Lockout</td><td>If an order is rejected, wait this amount of time before trying again</td></tr><tr><td>Time</td><td>End time of the algo, in your local timezone</td></tr></tbody></table>

The algo is not guaranteed to fill its full size by the end time, and will cancel any remainder size. Notably, it will not attempt to "catch-up" if orders are unfilled (e.g. due to rejects).


# Smart order router (SOR)

The Smart Order Router (SOR) will intelligently split an order among different venues based on the available liquidity in order to optimize execution price, and can make sense to use if liquidity is fragmented. This is available from the Trade tab, using the Smart order type.<br>

<figure><img src="/files/mltMDy8wmvdxmPM8R33Q" alt=""><figcaption><p>SOR evaluates the combined liquidity available on Coinbase and Kraken in order to optimize buying 1,000 SOL for a limit price of $195</p></figcaption></figure>

<figure><img src="/files/QCsj5QJEAF4BjbSBnhjx" alt=""><figcaption><p>The Smart Order Router then populates proposed orders, allocating a portion to each venue to best capture available liquidity. In this example, of the 1000 SOL parent order, ~596.8 SOL is sent to Kraken and ~403.2 SOL is sent to Coinbase.</p></figcaption></figure>

<table><thead><tr><th width="213">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>Buy/Sell</td><td>Direction of the order</td></tr><tr><td>Market</td><td>The symbol &#x26; price currency of the market will infer from the trading symbol of the trade page in the top left</td></tr><tr><td>Amount</td><td>Size of the order to execute, measured in token units</td></tr><tr><td>Limit Price</td><td>The price at which to send the orders</td></tr><tr><td>Duration</td><td>The execution time limit for the orders. Unfilled orders will cancel at the end of the duration.</td></tr><tr><td>Venues</td><td>Using the check boxes, select the different market/exchanges to use</td></tr></tbody></table>

After pressing "Get Quotes", the SOR algo will use the current order books in the selected markets to best allocate the parent order to optimize for price. The algo will simultaneously send the set of limit orders to the respective venues to maximize liquidity capture and reduce information leakage.&#x20;


# Percent of volume (POV)

The Percent of Volume (POV) algo attempts to spread out an order based on targeting a specified proportion of the overall market volume. An execution using the POV algo can reduce implementation costs by minimizing impact using a carefully managed, constant participation rate.&#x20;

<figure><img src="/files/zeSs9tddAv6J6rH4tzmG" alt=""><figcaption><p>In this POV example, the algo will target 2% of the ETH perpetual futures volume on Deribit. Between now and 04/01/2024 9:53 AM, the algo will buy as much as 500 ETH worth of perpetual futures, sending order at least 1 ETH size, 1 basis point above the offer in the futures market. The algo estimates a total cost of ~$1.7 million.</p></figcaption></figure>

We can choose the parameters based on the trading goals.&#x20;

<table><thead><tr><th width="213">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>Buy/Sell</td><td>Direction of the order</td></tr><tr><td>Market</td><td>The symbol &#x26; price currency of the market, and the exchange</td></tr><tr><td>Min Order Quantity</td><td>The smallest size order the algo will attempt to send</td></tr><tr><td>Max Quantity</td><td>The maximum quantity that will execute, measured in token units or contracts. Given enough time and market volume, this can also be thought of as the total quantity.</td></tr><tr><td>Take Through Fraction</td><td>At what price to send the order, relative to the opposite side market.  For example on a buy order, a take through fraction of 0 would send bids at a price equal to the best offer at the time, and a take through fraction of 0.0005 would send bids 0.05% (5 basis points) above the current offer. Increasing this parameter above 0 reduces the chance of missing out on trades in a fast moving market, but has a higher risk of price slippage. </td></tr><tr><td>Order Lockout</td><td>The minimum amount of time to wait between orders</td></tr><tr><td>Reject Lockout</td><td>If an order is rejected, wait this amount of time before trying again</td></tr><tr><td>Time</td><td>The end time of the algo, in your local timezone</td></tr></tbody></table>

If there's an insufficient volume of trading in the market, the algo is not guaranteed to fill its full size by the end time, and will cancel any remainder size. The algo can also conclude prior to the end time if the max quantity is reached.


# Market maker (MM)

The Market Maker (MM) algo provides liquidity in a designated market by sending orders on both sides of the market, using the midpoint of the current market as the reference price, and fade to maintain a neutral position.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeAUlgqmwkYTmKcyTbHKL%2Fuploads%2F3WF1kSeXo0Yk5267vli0%2Fimage.png?alt=media&#x26;token=ba3e631b-2afd-403e-ac69-ff437717d5a1" alt=""><figcaption><p>Market Maker (MM) algo in the AVAX/USDT market on Binance. Will send size 0.25 AVAX orders 0.1% away on each side, and will cancel/replace if market moves by 0.025%. As MM algo picks up positions, fade quotes by 0.05 USDT per 1 AVAX position accumulated, and will not send orders to exceed a total position of 10 AVAX.</p></figcaption></figure>

| Parameter                   | Description                                                                                                                                                                                                                             |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Market                      | Symbol & price currency of the market, as well as the exchange                                                                                                                                                                          |
| Buy/Sell Quantity           | Size of each order to send                                                                                                                                                                                                              |
| Minimum/Maximum Position    | Position bounds that the algo will not exceed. Will only send one sided orders the cumulative position reaches the minimum or maximum.                                                                                                  |
| Max Improve BBO             | Most an order can be more aggressive than the current best bid or offer. Can prevent order from being too tight inside current spread.                                                                                                  |
| Position Tilt               | The amount order prices should shift as a position is accumulated. For example, if MM algo net buys tokens, this will lower the price of bids & offers to fade the market. Measured in price change per unit.                           |
| Reference Distance Fraction | Distance away from reference price to send orders. For example if Reference Distance Fraction is 0.01, the bid and offer order sent will be 1% around the current reference price (and thus 2% wide).                                   |
| Tolerance Fraction          | Amount a new order would differ from current order to cancel and replace. Used to prevent flickering quotes and unnecessary cancel and replace, as well as maintaining queue priority. Measured as a fraction, i.e. not in price terms. |
| Order Lockout               | Minimum amount of time to wait between orders                                                                                                                                                                                           |
| Fill Lockout                | Amount of time to wait after a trade to send a new order                                                                                                                                                                                |
| Reject Lockout              | If an order is rejected, wait this amount of time before trying again                                                                                                                                                                   |


# Spreader (MM\*)

The Spreader algo market makes and trades one market based on another market. This can be used for a variety of different strategies, including cross-exchange arbitrage, futures vs spot basis trading, and relative value trading. Spreader will also send orders in the hedge market, and thus is able to lay off risk or complete the legs of an arbitrage trade.&#x20;

<figure><img src="/files/4lVsqCvaouEjuH9Q9fiP" alt=""><figcaption><p>Pricing the AAVE/USD market on Coinbase using the quotes from AAVE/USDT on Binance</p></figcaption></figure>

<figure><img src="/files/kWJSOaVWnqlSSBuZiixA" alt=""><figcaption><p>Trading quarterly Bitcoin future on Deribit based on spot BTC/USDT market on Binance, using a computed premium (future basis)  </p></figcaption></figure>

<table><thead><tr><th width="213">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>Market</td><td>Symbol &#x26; price currency &#x26; exchange of the primary market</td></tr><tr><td>Hedge Market</td><td>Symbol &#x26; price currency &#x26; exchange of the hedge market. The Hedge Market is the source of the reference price as well where hedging orders are sent</td></tr><tr><td>Conversion Ratio &#x26; Premium</td><td>The factors to relate the Market to the Hedge Market, using the formula: <br><code>Market Price = Hedge Market Price * Conversion Ratio + Premium</code><br>The Conversion Ratio also determines the quantity of the Hedge Market order sent for each fill in Market</td></tr><tr><td>Buy/Sell Quantity</td><td>Size of each order to send</td></tr><tr><td>Minimum/Maximum Position</td><td>Position bounds that the algo will not exceed. Will only send one sided orders the cumulative position reaches the minimum or maximum.</td></tr><tr><td>Max Improve BBO</td><td>Most an order can be more aggressive than the current best bid or offer. Can prevent order from being too tight inside current spread.</td></tr><tr><td>Position Tilt</td><td>The amount order prices should shift as a position is accumulated. For example, if MM algo net buys tokens, this will lower the price of bids &#x26; offers to fade the market. Measured in price change per unit.</td></tr><tr><td>Reference Distance Fraction</td><td>Distance away from reference price to send orders. For example if Reference Distance Fraction is 0.01, the bid and offer order sent will be 1% around the current reference price (and thus 2% wide).</td></tr><tr><td>Tolerance Fraction</td><td>Amount a new order would differ from current order to cancel and replace. Used to prevent flickering quotes and unnecessary cancel and replace, as well as maintaining queue priority. Measured as a fraction, i.e. not in price terms.</td></tr><tr><td>Order Lockout</td><td>Minimum amount of time to wait between orders</td></tr><tr><td>Fill Lockout</td><td>Amount of time to wait after a trade to send a new order</td></tr><tr><td>Reject Lockout</td><td>If an order is rejected, wait this amount of time before trying again</td></tr></tbody></table>

Upon getting a fill in the Market, Spreader algo will then trade in the Hedge Market (based on the Conversion Ratio). For the above examples, if Spreader buys AAVE on Coinbase it will then sell AAVE on Binance, or if Spreader buys BTC quarterly futures on Deribit it will sell spot BTC on Binance.


# One Triggers Other (OTO)

An OTO order consists of a primary order and one or more secondary orders that are triggered only after the primary order is filled.

### Triggering Behavior

* The `primary` order is placed immediately when the algo starts
* &#x20;The `secondary` orders are only placed after the `primary` order is filled&#x20;
* If `trigger_in_proportion` is true, the other orders are triggered proportionally based on the fill quantity of the primary order. The quantities are rounded down where necessary
  * For example, if `primary` has quantity 10, and `secondary` is a single order of quantity 5, then if `primary` is filled 5 lots and `trigger_in_proportion` is true, `other` will fire for 2 lots: (5/10) \* 5 = 2.5, rounded down
  * If `primary` subsequently receives another fill for 5 lots, `secondary` will fire its remaining 3 lots, and the algo will complete once `secondary` gets that filled
* If `trigger_in_proportion` is false, the other orders are only triggered after the primary order is completely filled

The OTO algo completes when:

* If `primary` is OUT and `secondary`  are [OUT](https://docs.architect.co/concepts/orderflow) /cancelled/rejected
* If `primary` is rejected or at any point cancelled.&#x20;

{% hint style="warning" %}
You cannot modify the algo once it is sent, you must cancel and send a new one if you want different parameters. You also cannot pause the algo, it will just cancel when you send a pause.
{% endhint %}

### Use Cases

* Executing a hedging strategy after an initial position is established
* Implementing conditional order sequences where subsequent orders depend on initial fills

### OneTriggersOtherParams

| Parameter                        | Description                                                                                                                                                                                             |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| primary *(OrderInfo)*            | Designate your `primary` order, which is placed immediately upon algo start. See [OrderInfo](#orderinfo).                                                                                               |
| secondary *(List\[OrderInfo])*   | A list of orders (use a singleton list for just one order) that will simultaneously trigger after the `primary` order is filled (depending on `trigger_in_proportion`).                                 |
| trigger\_in\_proportion *(bool)* | If true, `secondary` orders are triggered proportionally based on the fill quantity of the `primary` order. If false, `secondary` orders are only placed once the `primary` order is completely filled. |

### OrderInfo

OrderInfo is very similar to a [PlaceOrderRequest](https://docs.architect.co/sdk-reference/order-entry#order-request-fields). This contains the order information for each leg of the OTO algo. Note that you cannot nest other algos.

<table><thead><tr><th width="166.6875">Field</th><th width="104.08984375">Required</th><th>Description</th></tr></thead><tbody><tr><td>symbol</td><td>Y</td><td>Tradable product</td></tr><tr><td>dir</td><td>Y</td><td>Order side; BUY or SELL</td></tr><tr><td>quantity</td><td>Y</td><td>Order quantity</td></tr><tr><td>order_type</td><td>Y</td><td>Order type (Limit, Stop-loss, Market)</td></tr><tr><td>limit_price</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>post_only</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>trigger_price</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>time_in_force</td><td>Y</td><td>Order time-in-force instruction</td></tr><tr><td>execution_venue</td><td>Y</td><td>Execution venue for the order. Unlike PlaceOrderRequest, this is required</td></tr></tbody></table>

### Example

```python
from architect_py import (
    OneTriggersOtherParams,
    OrderInfo,
    OrderDir,
    TimeInForce,
    OrderType,
)

symbol1 = 'NQ 20251219 CME Future' 
symbol2 = 'MNQ 20251219 CME Future'
tp1 = f"{symbol1}/USD"
tp2 = f"{symbol2}/USD"
account = "PAPER:example@email.com"
venue = "CME"
params = OneTriggersOtherParams.new(
    primary=OrderInfo.new(
        symbol=tp1,
        execution_venue=venue, 
        dir=OrderDir.BUY, 
        quantity=10, 
        limit_price=24940,
        post_only=False,
        time_in_force=TimeInForce.IOC,
        order_type=OrderType.LIMIT,
    ),
    secondary= [
        OrderInfo.new(
            symbol=tp2,
            execution_venue=venue, 
            dir=OrderDir.SELL, 
            quantity=100, 
            limit_price=25000,
            post_only=False,
            time_in_force=TimeInForce.IOC,
            order_type=OrderType.LIMIT,
        )
    ],
    trigger_in_proportion=True,
)

order = await client.place_algo_order(params=params, account=account)
```


# One Cancels Other (OCO)

An OCO order consists of multiple orders where the fill of any one order automatically cancels all other orders in the group.

&#x20;All orders are placed simultaneously when the algo starts.

### Cancel Behavior

* When any order is fully filled, the remaining orders are immediately cancelled
* If `cancel_in_proportion` is **true**, partial fills trigger proportional cancellations of the remaining orders based on the fill quantity
  * This will be calculated based on "percent\_done", which is SUM(filled\_for\_a\_given\_order/order\_quantity) for all of the orders
  * For example, if you have three orders for quantities 10, 15, 20 and you have gotten filled on 1, 3, 10 respectively, you will have 1/10 + 3/15 + 10/20 = 80% done, so each order will have 20% left.\
    Thus, the remaining order quantities will be 2, 3, 4
  * Any fractional orders are rounded to the nearest quantity increment
* &#x20;If `cancel_in_proportion` is **false**, only a complete fill of one order triggers cancellation of all other orders

The OCO algo completes when:

* all orders are fully outed/cancelled

{% hint style="warning" %}
You **cannot modify the algo** once it is sent, you must cancel and send a new one if you want different parameters.

You also **cannot pause the algo**, it will just cancel when you send a pause.

If an order is rejected, the algo will continue operating with the remaining orders.

It is technically **possible for all orders to be filled** if they execute simultaneously
{% endhint %}

### Use Cases

* Placing orders on multiple exchanges where you only want one to execute
* Implementing profit target and stop loss orders simultaneously
* Managing risk by ensuring only one side of a position is filled

### OneCancelsOtherParams

| Parameter                       | Description                                                                                                                                                            |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| orders *(vec\<OrderInfo>)*      | The orders in the OCO set                                                                                                                                              |
| cancel\_in\_proportion *(bool)* | If true, orders are replaced proportionally based on the fill quantity of any given order. If false, orders are only cancelled once the an order is completely filled. |

### OrderInfo

OrderInfo is very similar to a [PlaceOrderRequest](https://docs.architect.co/sdk-reference/order-entry#order-request-fields). This contains the order information for each leg of the OCO algo.

<table><thead><tr><th width="166.6875">Field</th><th width="104.08984375">Required</th><th>Description</th></tr></thead><tbody><tr><td>symbol</td><td>Y</td><td>Tradable product</td></tr><tr><td>dir</td><td>Y</td><td>Order side; BUY or SELL</td></tr><tr><td>quantity</td><td>Y</td><td>Order quantity</td></tr><tr><td>order_type</td><td>Y</td><td>Order type</td></tr><tr><td>limit_price</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>post_only</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>trigger_price</td><td>N*</td><td>Required for certain order types</td></tr><tr><td>time_in_force</td><td>Y</td><td>Order time-in-force instruction</td></tr><tr><td>execution_venue</td><td>Y</td><td>Execution venue for the order. Unlike PlaceOrderRequest, this is required</td></tr></tbody></table>

### Example

```python
from architect_py import (
    OneTriggersOtherParams,
    OrderInfo,
    OrderDir,
    TimeInForce,
    OrderType,
)

symbol1 = 'NQ 20251219 CME Future' 
symbol2 = 'MNQ 20251219 CME Future'
tp1 = f"{symbol1}/USD"
tp2 = f"{symbol2}/USD"
account = "PAPER:example@email.com"
venue = "CME"
params = OneCancelsOtherParams.new(
    orders=[OrderInfo.new(
        symbol=tp1,
        execution_venue=venue, 
        dir=OrderDir.BUY, 
        quantity=10, 
        limit_price=24940,
        post_only=False,
        time_in_force=TimeInForce.IOC,
        order_type=OrderType.LIMIT,
        ),
        OrderInfo.new(
            symbol=tp2,
            execution_venue=venue, 
            dir=OrderDir.SELL, 
            quantity=100, 
            limit_price=25000,
            post_only=False,
            time_in_force=TimeInForce.IOC,
            order_type=OrderType.LIMIT,
        )
    ],
    cancel_in_proportion=True,
)

order = await client.place_algo_order(params=params, account=account)
```


# Bracket

A bracket order consists of an entry limit order, a take-profit order, and a stop-loss order.\
The take-profit and stop-loss orders are managed via a One-Cancels-Other (OCO) algo as a subalgo.<br>

&#x20;All orders are placed simultaneously when the algo starts.

### Order Structure

* **Entry Order**: A limit order that initiates the position
* **Take-Profit Order**: A limit order placed at `take_profit_price` to exit at a profit
* **Stop-Loss Order**: A stop-limit order with `stop_loss_trigger_price` and `stop_loss_limit_price` to exit at a loss

### Execution Behavior

1. The entry order is placed immediately when the algo starts
2. When the entry order receives fills, the exit orders (take-profit and stop-loss) are placed as an OCO pair
3. If `trigger_in_proportion` is true, exit orders are sized proportionally to the filled quantity of the entry order
4. If `trigger_in_proportion` is false, exit orders are only placed after the entry order is fully filled
5. When either exit order is filled, the other is immediately cancelled via the OCO subalgo

### Price Validation

**For BUY entries:**

* `take_profit_price` must be greater than entry `limit_price`
* `stop_loss_trigger_price` must be less than entry `limit_price`
* `stop_loss_limit_price` must be less than or equal to `stop_loss_trigger_price`

**For SELL entries:**

* `take_profit_price` must be less than entry `limit_price`
* `stop_loss_trigger_price` must be greater than entry `limit_price`
* `stop_loss_limit_price` must be greater than or equal to `stop_loss_trigger_price`

### &#x20;Completion

The bracket algo completes when:

* The entry order is outed/cancelled before any fills, OR
* All exit orders are fully filled or cancelled after entry fills

{% hint style="warning" %}
You **cannot modify the algo** once it is sent, you must cancel and send a new one if you want different parameters.

You also **cannot pause the algo**, it will just cancel when you send a pause.

It is technically **possible for both secondary orders to be filled** if they execute simultaneously
{% endhint %}

### Use Cases

* Automating profit-taking and risk management for a position
* Ensuring disciplined exits without manual intervention
* Managing trades with predefined risk/reward ratios

### BracketParams

| Parameter                                                               | Description                                                  |
| ----------------------------------------------------------------------- | ------------------------------------------------------------ |
| entry *(*[*OrderInfo*](/algos-book/one-triggers-other-oto#orderinfo)*)* | The entry order information                                  |
| take\_profit\_price *(Decimal)*                                         | Limit price for the take-profit exit order                   |
| stop\_loss\_trigger\_price (*Decimal*)                                  | Trigger price for the stop-loss order                        |
| stop\_loss\_limit\_price (*Decimal*)                                    | Limit price for the stop-loss order (after triggered)        |
| trigger\_in\_proportion (bool)                                          | If true, exit orders are sized proportionally to entry fills |

### Example

```python
from architect_py import (
    BracketParams,
    OrderInfo,
    OrderDir,
    TimeInForce,
    OrderType,
)

symbol = 'NQ 20251219 CME Future'
tp = f"{symbol}/USD"
account = "PAPER:example@email.com"
venue = "CME"

params = BracketParams.new(
    entry=OrderInfo.new(
        symbol=tp,
        execution_venue=venue,
        dir=OrderDir.BUY,
        quantity=10,
        limit_price=24940,
        post_only=False,
        time_in_force=TimeInForce.GTC,
        order_type=OrderType.LIMIT,
    ),
    take_profit_price=25100,
    stop_loss_trigger_price=24800,
    stop_loss_limit_price=24790,
    trigger_in_proportion=True,
)


order = await client.place_algo_order(params=params, account=account)
```


