DEV Community

Arnold Holm
Arnold Holm

Posted on

Alpaca partial fills: count 7 shares, not 10

Your bot should count 7 filled shares after totals of 3 and 7, not 10. In my small local check, adding both totals overstated the order by three shares. That is enough to give you the wrong view of how much of an order remains open.

In A Good Price Is Not Yet a Trade, Sergei B asks: "Which orders went into the count?" His post separates orders with some filled volume from orders with none. That distinction also matters when you read a bot's filled quantity. A good fill price says little if the quantity beside it has been counted twice.

This example uses invented quantities. It does not use Sergei's trading records or claim to repeat his measurement.

Two messages do not mean two new trades

Suppose you ask your bot to buy seven shares. The first message says three have filled. A later message says seven have filled in total. The later seven includes the first three. Only four more shares have filled between those messages.

Alpaca's trade-update documentation distinguishes the quantity of an individual execution, qty, from the order's total filled quantity, filled_qty. Check which field your bot stores before changing the calculation. Adding new executions and reading order totals are different ways to answer the same narrow quantity question.

Message Shares in this execution Total shares filled for the order
First partial fill 3 3
Final fill 4 7

You can add the two distinct executions: three plus four makes seven. Or you can read the latest authoritative order total: seven. Adding the two order totals gives ten, which counts the first three twice.

I keep an order's running filled quantity separate from each individual execution. I would stop on an unexplained lower total rather than quietly change the number shown to the trader.

What my local check found

I ran six checks with invented inputs. The first sequence reported three, then seven, and kept seven as the order total. Repeating seven added zero. A second order kept its own quantity. A lower total, a negative quantity and a non-number each stopped the calculation without changing the first order's seven shares.

Actual local check: seven shares counted correctly; adding the two reported totals gives ten. Six checks passed.

The picture comes from the output of that local run. The bar marked ten shows the incorrect addition of the two reported totals. It is not an order sent to a broker. You can reproduce the core calculation with Python's standard library:

from decimal import Decimal

class Reconcile(Exception):
    pass

def observe_total(totals, order_id, filled_qty):
    total = Decimal(filled_qty)
    if not total.is_finite() or total < 0:
        raise Reconcile("invalid filled quantity")
    previous = totals.get(order_id, Decimal("0"))
    if total < previous:
        raise Reconcile("lower total: reconcile before changing state")
    totals[order_id] = total
    return total - previous

totals = {}
assert observe_total(totals, "order-A", "3") == 3
assert observe_total(totals, "order-A", "7") == 4
assert observe_total(totals, "order-A", "7") == 0
assert totals.get("order-A") == 7
Enter fullscreen mode Exit fullscreen mode

Check one order in your own history

Compare one order's latest filled total with the sum of its distinct executions, keeping the order identifier the same. Do this on exported history or demo data before changing a running bot. Keep the message order and any execution identifiers with the values, so a repeated message cannot look like a new trade.

Also compare the filled amount with what you originally requested. Seven filled shares out of a seven-share request leaves none open in this example. Three filled out of seven leaves four. Do not mark the whole requested quantity as completed just because one part filled at a good price.

If a later message shows six after seven, investigate. It may be old information, a correction or a mapping mistake. This short check cannot choose between those explanations. Keeping the larger value forever would hide a real correction; trusting whichever message arrives last would hide a delayed one.

This is a check of one order's quantities, not your account's position or a trading result. The code has no lasting storage, reconnect handling or full account comparison, and restarting it loses the dictionary. The six local checks do not establish that a live bot is ready.

If your bot's order history disagrees with its dashboard, the bot repair page gives you a place to describe the expected and actual behaviour. Keep account identifiers and access details out of public comments.

Top comments (0)