11/**
22 * UTA — Alpaca paper lifecycle e2e.
33 *
4- * Full Trading-as-Git flow: stage → commit → push → sync → verify
5- * against Alpaca paper trading (US equities).
6- *
7- * Skips when market is closed — Alpaca paper won't fill orders outside trading hours.
4+ * Two groups:
5+ * - Order lifecycle (any time): limit order stage → commit → push → cancel
6+ * - Full fill flow (market hours): market order → fill → verify → close
87 *
98 * Run: pnpm test:e2e
109 */
@@ -15,27 +14,77 @@ import { UnifiedTradingAccount } from '../../UnifiedTradingAccount.js'
1514import type { IBroker } from '../../brokers/types.js'
1615import '../../contract-ext.js'
1716
18- describe ( 'UTA — Alpaca lifecycle (AAPL)' , ( ) => {
19- let broker : IBroker | null = null
20- let marketOpen = false
21-
22- beforeAll ( async ( ) => {
23- const all = await getTestAccounts ( )
24- const alpaca = filterByProvider ( all , 'alpaca' ) [ 0 ]
25- if ( ! alpaca ) return
26- broker = alpaca . broker
27- const clock = await broker . getMarketClock ( )
28- marketOpen = clock . isOpen
29- console . log ( `UTA Alpaca: market ${ marketOpen ? 'OPEN' : 'CLOSED' } ` )
30- } , 60_000 )
17+ let broker : IBroker | null = null
18+ let marketOpen = false
19+
20+ beforeAll ( async ( ) => {
21+ const all = await getTestAccounts ( )
22+ const alpaca = filterByProvider ( all , 'alpaca' ) [ 0 ]
23+ if ( ! alpaca ) return
24+ broker = alpaca . broker
25+ const clock = await broker . getMarketClock ( )
26+ marketOpen = clock . isOpen
27+ console . log ( `UTA Alpaca: market ${ marketOpen ? 'OPEN' : 'CLOSED' } ` )
28+ } , 60_000 )
29+
30+ // ==================== Order lifecycle (any time) ====================
31+
32+ describe ( 'UTA — Alpaca order lifecycle' , ( ) => {
33+ beforeEach ( ( { skip } ) => { if ( ! broker ) skip ( 'no Alpaca paper account' ) } )
34+
35+ it ( 'limit order: stage → commit → push → cancel' , async ( ) => {
36+ const uta = new UnifiedTradingAccount ( broker ! )
37+ const nativeKey = broker ! . getNativeKey ( { symbol : 'AAPL' } as any )
38+ const aliceId = `${ uta . id } |${ nativeKey } `
39+
40+ // Stage a limit buy at $1 (won't fill)
41+ const addResult = uta . stagePlaceOrder ( {
42+ aliceId,
43+ symbol : 'AAPL' ,
44+ side : 'buy' ,
45+ type : 'limit' ,
46+ price : 1.00 ,
47+ qty : 1 ,
48+ timeInForce : 'gtc' ,
49+ } )
50+ expect ( addResult . staged ) . toBe ( true )
51+
52+ const commitResult = uta . commit ( 'e2e: limit buy 1 AAPL @ $1' )
53+ expect ( commitResult . prepared ) . toBe ( true )
54+ console . log ( ` committed: hash=${ commitResult . hash } ` )
55+
56+ const pushResult = await uta . push ( )
57+ console . log ( ` pushed: submitted=${ pushResult . submitted . length } , status=${ pushResult . submitted [ 0 ] ?. status } ` )
58+ expect ( pushResult . submitted ) . toHaveLength ( 1 )
59+ expect ( pushResult . rejected ) . toHaveLength ( 0 )
60+ expect ( pushResult . submitted [ 0 ] . orderId ) . toBeDefined ( )
61+
62+ const orderId = pushResult . submitted [ 0 ] . orderId !
63+
64+ // Cancel the order
65+ uta . stageCancelOrder ( { orderId } )
66+ uta . commit ( 'e2e: cancel limit order' )
67+ const cancelPush = await uta . push ( )
68+ console . log ( ` cancel pushed: submitted=${ cancelPush . submitted . length } , status=${ cancelPush . submitted [ 0 ] ?. status } ` )
69+ expect ( cancelPush . submitted ) . toHaveLength ( 1 )
70+
71+ // Verify log has 2 commits
72+ expect ( uta . log ( ) . length ) . toBeGreaterThanOrEqual ( 2 )
73+ } , 30_000 )
74+ } )
75+
76+ // ==================== Full fill flow (market hours only) ====================
3177
78+ describe ( 'UTA — Alpaca fill flow (AAPL)' , ( ) => {
3279 beforeEach ( ( { skip } ) => {
3380 if ( ! broker ) skip ( 'no Alpaca paper account' )
3481 if ( ! marketOpen ) skip ( 'market closed' )
3582 } )
3683
3784 it ( 'buy → sync → verify → close → sync → verify' , async ( ) => {
3885 const uta = new UnifiedTradingAccount ( broker ! )
86+ const nativeKey = broker ! . getNativeKey ( { symbol : 'AAPL' } as any )
87+ const aliceId = `${ uta . id } |${ nativeKey } `
3988
4089 // Record initial state
4190 const initialPositions = await broker ! . getPositions ( )
@@ -44,7 +93,7 @@ describe('UTA — Alpaca lifecycle (AAPL)', () => {
4493
4594 // === Stage + Commit + Push: buy 1 AAPL ===
4695 const addResult = uta . stagePlaceOrder ( {
47- aliceId : ` ${ uta . id } |AAPL` ,
96+ aliceId,
4897 symbol : 'AAPL' ,
4998 side : 'buy' ,
5099 type : 'market' ,
@@ -79,7 +128,7 @@ describe('UTA — Alpaca lifecycle (AAPL)', () => {
79128 expect ( aaplPos ! . quantity . toNumber ( ) ) . toBe ( initialAaplQty + 1 )
80129
81130 // === Close 1 AAPL ===
82- uta . stageClosePosition ( { aliceId : ` ${ uta . id } |AAPL` , qty : 1 } )
131+ uta . stageClosePosition ( { aliceId, qty : 1 } )
83132 uta . commit ( 'e2e: close 1 AAPL' )
84133 const closePush = await uta . push ( )
85134 console . log ( ` close pushed: status=${ closePush . submitted [ 0 ] ?. status } ` )
0 commit comments