diff --git a/invstmt_test.go b/invstmt_test.go
new file mode 100644
index 0000000..0a97a32
--- /dev/null
+++ b/invstmt_test.go
@@ -0,0 +1,559 @@
+package ofxgo_test
+
+import (
+ "github.com/aclindsa/ofxgo"
+ "math/big"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestMarshalInvStatementRequest(t *testing.T) {
+ var expectedString string = `
+
+
+
+
+ 20160224131905.000[-5:EST]
+ 1998124
+ Sup3eSekrit
+ ENG
+
+ First Bank
+ 01
+
+ MYAPP
+ 1234
+
+
+
+
+ 382827d6-e2d0-4396-bf3b-665979285420
+
+
+ fi.example.com
+ 82736664
+
+
+ 20160101000000.000[-5:EST]
+ Y
+
+ Y
+
+ Y
+
+ Y
+
+
+
+`
+
+ var client = ofxgo.Client{
+ AppId: "MYAPP",
+ AppVer: "1234",
+ SpecVersion: "203",
+ }
+
+ var request ofxgo.Request
+ request.Signon.UserId = "1998124"
+ request.Signon.UserPass = "Sup3eSekrit"
+ request.Signon.Org = "First Bank"
+ request.Signon.Fid = "01"
+
+ EST := time.FixedZone("EST", -5*60*60)
+ dtstart := ofxgo.Date(time.Date(2016, 1, 1, 0, 0, 0, 0, EST))
+
+ statementRequest := ofxgo.InvStatementRequest{
+ TrnUID: "382827d6-e2d0-4396-bf3b-665979285420",
+ InvAcctFrom: ofxgo.InvAcct{
+ BrokerId: "fi.example.com",
+ AcctId: "82736664",
+ },
+ DtStart: &dtstart,
+ Include: true,
+ IncludeOO: true,
+ IncludePos: true,
+ IncludeBalance: true,
+ }
+ request.InvStmt = append(request.InvStmt, &statementRequest)
+
+ request.SetClientFields(&client)
+ // Overwrite the DtClient value set by SetClientFields to time.Now()
+ request.Signon.DtClient = ofxgo.Date(time.Date(2016, 2, 24, 13, 19, 5, 0, EST))
+
+ marshalCheckRequest(t, &request, expectedString)
+}
+
+func TestUnmarshalInvStatementResponse(t *testing.T) {
+ responseReader := strings.NewReader(`
+
+
+
+
+
+ 0
+ INFO
+
+ 20170401201244
+ ENG
+
+ INVSTRUS
+ 9999
+
+
+
+
+
+ 1a0117ad-692b-4c6a-a21b-020d37d34d49
+
+ 0
+ INFO
+
+
+ 20170331000000
+ USD
+
+ invstrus.com
+ 91827364
+
+
+ 20170101000000
+ 20170331000000
+
+
+
+ 729483191
+ 20170203
+ 20170207
+
+
+ 78462F103
+ CUSIP
+
+ 100
+ 229.00
+ 9.00
+ -22909.00
+ CASH
+ CASH
+
+ BUY
+
+
+
+ CREDIT
+ 20170120
+ 20170118
+ 20170123
+ 22000.00
+ 993838
+ DEPOSIT
+ CHECK 19980
+
+ CASH
+
+
+
+
+
+
+ 78462F103
+ CUSIP
+
+ CASH
+ LONG
+ 200
+ 235.74
+ 47148.00
+ 20170331160000
+ Price as of previous close
+
+
+
+
+
+ 129887339
+ CUSIP
+
+ CASH
+ LONG
+ 1
+ 3
+ 300
+ 20170331160000
+
+
+
+
+ 16.73
+ -819.20
+ 0
+
+
+ Sweep Int Rate
+ Current interest rate for sweep account balances
+ PERCENT
+ 0.25
+ 20170401
+
+
+
+
+
+
+ 76464632
+
+ 922908645
+ CUSIP
+
+ 20170310124445
+ 10
+ CASH
+ GOODTILCANCEL
+ NONE
+ 168.50
+
+ BUY
+ SHARES
+
+
+
+ 999387423
+
+ 899422348
+ CUSIP
+
+ 20170324031900
+ 25
+ CASH
+ GOODTILCANCEL
+ ALLORNONE
+ 19.75
+
+ BUY
+
+
+
+
+
+
+
+
+
+
+ 78462F103
+ CUSIP
+
+ S&P 500 ETF
+ SPY
+ 99184
+
+ 1.92
+ OTHER
+
+
+
+
+ 129887339
+ CUSIP
+
+ John's Fertilizer Puts
+ FERTP
+ 882919
+
+ PUT
+ 79.00
+ 20170901
+ 100
+
+ 983322180
+ CUSIP
+
+ LARGESTOCK
+
+
+
+
+ 899422348
+ CUSIP
+
+ Whatchamacallit, Inc.
+ WHAT
+ 883897
+
+ 17
+ SMALLSTOCK
+
+
+
+
+ 922908645
+ CUSIP
+
+ Mid-Cap Index Fund Admiral Shares
+ VIMAX
+
+
+
+
+`)
+ var expected ofxgo.Response
+ GMT := time.FixedZone("GMT", 0)
+
+ expected.Version = "203"
+ expected.Signon.Status.Code = 0
+ expected.Signon.Status.Severity = "INFO"
+ expected.Signon.DtServer = ofxgo.Date(time.Date(2017, 4, 1, 20, 12, 44, 0, GMT))
+ expected.Signon.Language = "ENG"
+ expected.Signon.Org = "INVSTRUS"
+ expected.Signon.Fid = "9999"
+
+ var units1, unitprice1, commission1, total1, amount2 big.Rat
+ units1.SetFrac64(100, 1)
+ unitprice1.SetFrac64(229, 1)
+ commission1.SetFrac64(9, 1)
+ total1.SetFrac64(-22909, 1)
+ amount2.SetFrac64(22000, 1)
+
+ dtuser := ofxgo.Date(time.Date(2017, 1, 18, 0, 0, 0, 0, GMT))
+ dtavail := ofxgo.Date(time.Date(2017, 1, 23, 0, 0, 0, 0, GMT))
+ dtsettle := ofxgo.Date(time.Date(2017, 2, 7, 0, 0, 0, 0, GMT))
+
+ invtranlist := ofxgo.InvTranList{
+ DtStart: ofxgo.Date(time.Date(2017, 1, 1, 0, 0, 0, 0, GMT)),
+ DtEnd: ofxgo.Date(time.Date(2017, 3, 31, 0, 0, 0, 0, GMT)),
+ InvTransactions: []ofxgo.InvTransaction{
+ ofxgo.BuyStock{
+ InvBuy: ofxgo.InvBuy{
+ InvTran: ofxgo.InvTran{
+ FiTId: "729483191",
+ DtTrade: ofxgo.Date(time.Date(2017, 2, 3, 0, 0, 0, 0, GMT)),
+ DtSettle: &dtsettle,
+ },
+ SecId: ofxgo.SecurityId{
+ UniqueId: "78462F103",
+ UniqueIdType: "CUSIP",
+ },
+ Units: ofxgo.Amount(units1),
+ UnitPrice: ofxgo.Amount(unitprice1),
+ Commission: ofxgo.Amount(commission1),
+ Total: ofxgo.Amount(total1),
+ SubAcctSec: "CASH",
+ SubAcctFund: "CASH",
+ },
+ BuyType: "BUY",
+ },
+ },
+ BankTransactions: []ofxgo.InvBankTransaction{
+ ofxgo.InvBankTransaction{
+ Transactions: []ofxgo.Transaction{
+ ofxgo.Transaction{
+ TrnType: "CREDIT",
+ DtPosted: ofxgo.Date(time.Date(2017, 1, 20, 0, 0, 0, 0, GMT)),
+ DtUser: &dtuser,
+ DtAvail: &dtavail,
+ TrnAmt: ofxgo.Amount(amount2),
+ FiTId: "993838",
+ Name: "DEPOSIT",
+ Memo: "CHECK 19980",
+ },
+ },
+ SubAcctFund: "CASH",
+ },
+ },
+ }
+
+ var availcash, marginbalance, shortbalance, balvalue big.Rat
+ availcash.SetFrac64(1673, 100)
+ marginbalance.SetFrac64(-8192, 10)
+ shortbalance.SetFrac64(0, 1)
+ balvalue.SetFrac64(25, 100)
+
+ baldtasof := ofxgo.Date(time.Date(2017, 4, 1, 0, 0, 0, 0, GMT))
+
+ invbalance := ofxgo.InvBalance{
+ AvailCash: ofxgo.Amount(availcash),
+ MarginBalance: ofxgo.Amount(marginbalance),
+ ShortBalance: ofxgo.Amount(shortbalance),
+ BalList: []ofxgo.Balance{
+ ofxgo.Balance{
+ Name: "Sweep Int Rate",
+ Desc: "Current interest rate for sweep account balances",
+ BalType: "PERCENT",
+ Value: ofxgo.Amount(balvalue),
+ DtAsOf: &baldtasof,
+ },
+ },
+ }
+
+ var balamt, availbalamt, posunits1, posunitprice1, posmktval1, posunits2, posunitprice2, posmktval2, oounits1, oolimitprice1, oounits2, oolimitprice2 big.Rat
+ balamt.SetFrac64(20029, 100)
+ availbalamt.SetFrac64(20029, 100)
+ posunits1.SetFrac64(200, 1)
+ posunitprice1.SetFrac64(23574, 100)
+ posmktval1.SetFrac64(47148, 1)
+ posunits2.SetFrac64(1, 1)
+ posunitprice2.SetFrac64(3, 1)
+ posmktval2.SetFrac64(300, 1)
+ oounits1.SetFrac64(10, 1)
+ oolimitprice1.SetFrac64(16850, 100)
+ oounits2.SetFrac64(25, 1)
+ oolimitprice2.SetFrac64(1975, 100)
+
+ statementResponse := ofxgo.InvStatementResponse{
+ TrnUID: "1a0117ad-692b-4c6a-a21b-020d37d34d49",
+ Status: ofxgo.Status{
+ Code: 0,
+ Severity: "INFO",
+ },
+ DtAsOf: ofxgo.Date(time.Date(2017, 3, 31, 0, 0, 0, 0, GMT)),
+ CurDef: "USD",
+ InvAcctFrom: ofxgo.InvAcct{
+ BrokerId: "invstrus.com",
+ AcctId: "91827364",
+ },
+ InvTranList: &invtranlist,
+ InvPosList: ofxgo.PositionList{
+ ofxgo.StockPosition{
+ InvPos: ofxgo.InvPosition{
+ SecId: ofxgo.SecurityId{
+ UniqueId: "78462F103",
+ UniqueIdType: "CUSIP",
+ },
+ HeldInAcct: "CASH",
+ PosType: "LONG",
+ Units: ofxgo.Amount(posunits1),
+ UnitPrice: ofxgo.Amount(posunitprice1),
+ MktVal: ofxgo.Amount(posmktval1),
+ DtPriceAsOf: ofxgo.Date(time.Date(2017, 3, 31, 16, 0, 0, 0, GMT)),
+ Memo: "Price as of previous close",
+ },
+ },
+ ofxgo.OptPosition{
+ InvPos: ofxgo.InvPosition{
+ SecId: ofxgo.SecurityId{
+ UniqueId: "129887339",
+ UniqueIdType: "CUSIP",
+ },
+ HeldInAcct: "CASH",
+ PosType: "LONG",
+ Units: ofxgo.Amount(posunits2),
+ UnitPrice: ofxgo.Amount(posunitprice2),
+ MktVal: ofxgo.Amount(posmktval2),
+ DtPriceAsOf: ofxgo.Date(time.Date(2017, 3, 31, 16, 0, 0, 0, GMT)),
+ },
+ },
+ },
+ InvBal: &invbalance,
+ InvOOList: ofxgo.OOList{
+ ofxgo.OOBuyMF{
+ OO: ofxgo.OO{
+ FiTId: "76464632",
+ SecId: ofxgo.SecurityId{
+ UniqueId: "922908645",
+ UniqueIdType: "CUSIP",
+ },
+ DtPlaced: ofxgo.Date(time.Date(2017, 3, 10, 12, 44, 45, 0, GMT)),
+ Units: ofxgo.Amount(oounits1),
+ SubAcct: "CASH",
+ Duration: "GOODTILCANCEL",
+ Restriction: "NONE",
+ LimitPrice: ofxgo.Amount(oolimitprice1),
+ },
+ BuyType: "BUY",
+ UnitType: "SHARES",
+ },
+ ofxgo.OOBuyStock{
+ OO: ofxgo.OO{
+ FiTId: "999387423",
+ SecId: ofxgo.SecurityId{
+ UniqueId: "899422348",
+ UniqueIdType: "CUSIP",
+ },
+ DtPlaced: ofxgo.Date(time.Date(2017, 3, 24, 3, 19, 0, 0, GMT)),
+ Units: ofxgo.Amount(oounits2),
+ SubAcct: "CASH",
+ Duration: "GOODTILCANCEL",
+ Restriction: "ALLORNONE",
+ LimitPrice: ofxgo.Amount(oolimitprice2),
+ },
+ BuyType: "BUY",
+ },
+ },
+ }
+ expected.InvStmt = append(expected.InvStmt, &statementResponse)
+
+ var yield1, yield2, strikeprice big.Rat
+ yield1.SetFrac64(192, 100)
+ yield2.SetFrac64(17, 1)
+ strikeprice.SetFrac64(79, 1)
+
+ seclist := ofxgo.SecurityList{
+ Securities: []ofxgo.Security{
+ ofxgo.StockInfo{
+ SecInfo: ofxgo.SecInfo{
+ SecId: ofxgo.SecurityId{
+ UniqueId: "78462F103",
+ UniqueIdType: "CUSIP",
+ },
+ SecName: "S&P 500 ETF",
+ Ticker: "SPY",
+ FiId: "99184",
+ },
+ Yield: ofxgo.Amount(yield1),
+ AssetClass: "OTHER",
+ },
+ ofxgo.OptInfo{
+ SecInfo: ofxgo.SecInfo{
+ SecId: ofxgo.SecurityId{
+ UniqueId: "129887339",
+ UniqueIdType: "CUSIP",
+ },
+ SecName: "John's Fertilizer Puts",
+ Ticker: "FERTP",
+ FiId: "882919",
+ },
+ OptType: "PUT",
+ StrikePrice: ofxgo.Amount(strikeprice),
+ DtExpire: ofxgo.Date(time.Date(2017, 9, 1, 0, 0, 0, 0, GMT)),
+ ShPerCtrct: 100,
+ SecId: &ofxgo.SecurityId{
+ UniqueId: "983322180",
+ UniqueIdType: "CUSIP",
+ },
+ AssetClass: "LARGESTOCK",
+ },
+ ofxgo.StockInfo{
+ SecInfo: ofxgo.SecInfo{
+ SecId: ofxgo.SecurityId{
+ UniqueId: "899422348",
+ UniqueIdType: "CUSIP",
+ },
+ SecName: "Whatchamacallit, Inc.",
+ Ticker: "WHAT",
+ FiId: "883897",
+ },
+ Yield: ofxgo.Amount(yield2),
+ AssetClass: "SMALLSTOCK",
+ },
+ ofxgo.MFInfo{
+ SecInfo: ofxgo.SecInfo{
+ SecId: ofxgo.SecurityId{
+ UniqueId: "922908645",
+ UniqueIdType: "CUSIP",
+ },
+ SecName: "Mid-Cap Index Fund Admiral Shares",
+ Ticker: "VIMAX",
+ },
+ },
+ },
+ }
+ expected.SecList = append(expected.SecList, &seclist)
+
+ response, err := ofxgo.ParseResponse(responseReader)
+ if err != nil {
+ t.Fatalf("Unexpected error unmarshalling response: %s\n", err)
+ }
+
+ checkResponsesEqual(t, &expected, response)
+}