Live Trading Boundary의 남은 account-sync/audit-trail 작업을 완료해 운영자 headless workflow와 roadmap 완료 후보 상태를 함께 반영한다.
97 lines
2.6 KiB
Go
97 lines
2.6 KiB
Go
package trading
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"git.toki-labs.com/toki/alt/packages/domain/market"
|
|
)
|
|
|
|
func sampleAccountSnapshot() AccountSnapshot {
|
|
return AccountSnapshot{
|
|
Broker: BrokerKIS,
|
|
AccountID: "op-alias-001",
|
|
Cash: []CashBalance{
|
|
{Currency: market.CurrencyUSD, Amount: market.Decimal{Value: "1000"}},
|
|
{Currency: market.CurrencyKRW, Amount: market.Decimal{Value: "5000000"}},
|
|
},
|
|
Positions: []PositionSnapshot{
|
|
{
|
|
InstrumentID: "KRX:005930",
|
|
Side: OrderSideBuy,
|
|
Quantity: market.Quantity{Amount: market.Decimal{Value: "10"}},
|
|
},
|
|
},
|
|
SyncedAt: time.Date(2026, 6, 8, 0, 0, 0, 0, time.UTC),
|
|
Stale: false,
|
|
}
|
|
}
|
|
|
|
func TestSortCashBalancesIsStable(t *testing.T) {
|
|
snap := sampleAccountSnapshot()
|
|
// USD comes before KRW alphabetically; after sort KRW should be first.
|
|
SortCashBalances(snap.Cash)
|
|
if len(snap.Cash) != 2 {
|
|
t.Fatalf("expected 2 cash balances, got %d", len(snap.Cash))
|
|
}
|
|
if snap.Cash[0].Currency != market.CurrencyKRW {
|
|
t.Errorf("expected KRW first after sort, got %q", snap.Cash[0].Currency)
|
|
}
|
|
if snap.Cash[1].Currency != market.CurrencyUSD {
|
|
t.Errorf("expected USD second after sort, got %q", snap.Cash[1].Currency)
|
|
}
|
|
}
|
|
|
|
func TestSortCashBalancesEmptyIsNoop(t *testing.T) {
|
|
SortCashBalances(nil)
|
|
SortCashBalances([]CashBalance{})
|
|
}
|
|
|
|
func TestSortPositionSnapshotsIsStable(t *testing.T) {
|
|
positions := []PositionSnapshot{
|
|
{InstrumentID: "US:MSFT"},
|
|
{InstrumentID: "KRX:005930"},
|
|
}
|
|
SortPositionSnapshots(positions)
|
|
if positions[0].InstrumentID != "KRX:005930" {
|
|
t.Errorf("expected KRX:005930 first, got %q", positions[0].InstrumentID)
|
|
}
|
|
if positions[1].InstrumentID != "US:MSFT" {
|
|
t.Errorf("expected US:MSFT second, got %q", positions[1].InstrumentID)
|
|
}
|
|
}
|
|
|
|
func TestAccountSnapshotHasNoRawAccountNumber(t *testing.T) {
|
|
snap := sampleAccountSnapshot()
|
|
if HasRawAccountNumber(snap) {
|
|
t.Error("AccountSnapshot must not carry a raw account number")
|
|
}
|
|
}
|
|
|
|
func TestAccountSnapshotMultiCurrencyCashPreserved(t *testing.T) {
|
|
snap := sampleAccountSnapshot()
|
|
if len(snap.Cash) != 2 {
|
|
t.Errorf("expected 2 cash entries, got %d", len(snap.Cash))
|
|
}
|
|
foundKRW := false
|
|
foundUSD := false
|
|
for _, c := range snap.Cash {
|
|
if c.Currency == market.CurrencyKRW {
|
|
foundKRW = true
|
|
}
|
|
if c.Currency == market.CurrencyUSD {
|
|
foundUSD = true
|
|
}
|
|
}
|
|
if !foundKRW || !foundUSD {
|
|
t.Error("expected KRW and USD cash balances to be preserved")
|
|
}
|
|
}
|
|
|
|
func TestStaleSnapshotFlagIsPreserved(t *testing.T) {
|
|
snap := sampleAccountSnapshot()
|
|
snap.Stale = true
|
|
if !snap.Stale {
|
|
t.Error("expected Stale=true to be preserved")
|
|
}
|
|
}
|