Fix portfolio, account and order reads on the trading port - #1
Closed
simoneb wants to merge 3 commits into
Closed
Conversation
get_portfolio() sent GETPORTFOLIO and get_account_info() sent GETACCTINFO.
Darwin rejects both with ERR;<command>;1004, so neither call could ever
return data. Verified against Darwin 2.5.1:
> GETPORTFOLIO ERR;GETPORTFOLIO;1004
> INFOSTOCKS STOCK;<ticker>;<ora>;... (one line per position)
> GETACCTINFO ERR;GETACCTINFO;1004
> INFOACCOUNT INFOACCOUNT;<ora>;<conto>;...
The parsers were already written for the correct commands — the docstrings
of parse_portfolio_response and parse_account_info_response name INFOSTOCKS
and INFOACCOUNT respectively — so only the commands sent were wrong.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TradingConnection.send_command returned only the first line matching the expected prefix, discarding the rest of a multi-line response. Against a live account this meant ORDERLIST returned 4 orders on the socket and get_orders() returned 1, and a 15-position portfolio arrived as a single position. Nothing reported that data had been dropped. Two further problems fed into the same failure: - The read loop stopped at the first chunk containing a newline, so a list spanning several TCP reads was cut wherever the segment boundary fell. - Darwin pushes unsolicited traffic on this port: a full portfolio and order snapshot on connect, then position and order updates as they happen. Those lines were read as if they answered the command in flight, and pushed STOCK lines are indistinguishable from INFOSTOCKS rows. The response is now read line by line, with the leftover bytes buffered across calls, until the response is actually complete. Completion is determined by an end marker rather than by silence: connect() enables FLOWPOINT, so Darwin wraps list responses in BEGIN/END STOCKLIST and BEGIN/END ORDERLIST. If Darwin declines, the reader falls back to an idle gap and logs a warning. Lines are then selected by prefix, and a list command returns every matching row. The connect-time push is drained into TradingConnection.pushed_lines instead of being read as a response — it is a genuine snapshot, so it is kept rather than dropped. ERR codes 1024-1028 announce trading/datafeed link events and arrive unprompted; they no longer fail whichever command happens to be in flight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Covers the reads against a stand-in for Darwin's socket, so they can run without the platform: complete multi-line responses, lines split across TCP reads, the connect-time push not being mistaken for a response, link notifications not failing a command, and the two command names Darwin accepts. Response shapes follow a live Darwin 2.5.1; values are synthetic. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
simoneb
force-pushed
the
fix/trading-port-reads
branch
from
August 12, 2026 10:09
dc06c32 to
e4502fb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ciao! Ho usato questa libreria per costruire un server MCP verso Darwin e, testandola contro una piattaforma reale, ho trovato tre problemi sul percorso di lettura della porta di trading (10002) che la rendevano inutilizzabile per portafoglio, saldo e ordini. Tutto verificato su Darwin 2.5.1 (build 04/02/2025).
Il più insidioso non dà errore: perde dati in silenzio.
1. Due comandi che Darwin rifiuta
get_portfolio()inviaGETPORTFOLIOeget_account_info()inviaGETACCTINFO. Darwin rispondeERR;<comando>;1004a entrambi, quindi nessuna delle due chiamate può restituire dati:Curiosamente i parser erano già scritti per i comandi giusti: i docstring di
parse_portfolio_responseeparse_account_info_responsenominano proprioINFOSTOCKSeINFOACCOUNT. Era solo l'invio a essere sbagliato.Ho verificato anche che non fosse un problema di sinonimi:
GETACCOUNT,GETAVAILABILITY,INFOSTOCK(singolare),PORTFOLIO,INFOPOSITION,GETPENDINGORDERSeTABLEDESCRIPTIONrispondono tutti1004. FunzionanoINFOACCOUNT,INFOAVAILABILITY,INFOSTOCKS,GETPOSITION <sym>,ORDERLIST,ORDERLISTPENDING,DARWINSTATUS.2. Le risposte multi-riga venivano troncate alla prima riga
TradingConnection.send_commandrestituiva solo la prima riga corrispondente al prefisso atteso, scartando il resto. Misurato dal vivo su un conto con 15 posizioni e 4 record di ordine:send_commandORDERLISTINFOSTOCKSNessun errore, nessun warning: il chiamante riceve un portafoglio da una posizione e non ha modo di sapere che ne mancano 14. Su una libreria di trading mi è sembrato il problema più grave dei tre.
Due cause secondarie contribuivano allo stesso guasto:
recv()veniva tagliata dove cadeva il confine del segmento TCP.STOCKpushata è indistinguibile da una riga di risposta aINFOSTOCKS.3.
FLOWPOINT, per sapere dove finisce una listaSenza marker, una lista è solo una sequenza di righe e l'unico modo per sapere di averle tutte è aspettare il silenzio e sperare.
FLOWPOINT TRUErisolve: Darwin avvolge le liste inBEGIN/END.connect()ora lo abilita, così la lettura termina su un marker invece che su un timeout, e le righe pushate a metà risposta cadono fuori dai marker. Se Darwin rifiuta, si torna al fallback a intervallo di inattività con un warning nel log — nessuna regressione per chi ha una build che non lo supporta.Cosa cambia nel codice
TradingConnection.pushed_linesanziché essere letto come risposta. È uno snapshot legittimo del conto, quindi lo conservo invece di scartarlo.ERR1024-1028 segnalano eventi del collegamento trading/datafeed e arrivano non richiesti: non fanno più fallire il comando in volo.send_commandrestituisce ancora una stringa, e per i comandi a riga singola restituisce ancora una riga singola —parse_account_info_response, che fasplit(';')sull'intera risposta, continua a funzionare invariato.Test
Ho aggiunto
tests/test_trading_connection.py: 12 test contro un finto Darwin su socket, quindi girano in CI senza la piattaforma. Coprono le risposte complete, le righe spezzate tra letture TCP (chunk_size=4), il push iniziale non confuso con una risposta, le notifiche di link che non fanno fallire un comando, i due nomi di comando, e il fallback senzaFLOWPOINT. Le forme delle risposte seguono quelle reali; i valori sono sintetici.I 20 test (12 nuovi + 8 preesistenti di simulazione) passano.
Verificato anche end-to-end contro Darwin reale con la libreria patchata:
get_account_infoeget_portfoliotornano a restituire dati (prima:ERR 1004entrambi), eget_ordersrestituisce tutti i record invece di uno solo.Note
send_commandlegge fino aEND CANDLES/END TBTe non ha lo stesso difetto. Non ho comunque potuto vedere dati storici reali perché il conto usato non ha le quotazioni abilitate — ogni comando su 10003 risponde1032, coerentemente con il flag datafeedFALSEinDARWIN_STATUS.send_commandgestisca bene anche le risposteTRADOK/TRADERR/TRADCONFIRM, che con il mio fix passano dal ramo "prefisso non noto".FLOWPOINT— dimmelo e riorganizzo volentieri. Ho inclusoFLOWPOINTperché senza i marker le righe pushate restano indistinguibili da quelle di risposta, quindi il fix del troncamento da solo mi sembrava a metà.Grazie per aver pubblicato la libreria — avere il protocollo già mappato in Python mi ha fatto risparmiare un bel po' di lavoro.