package qqq import ( "git.beejay.kim/Gshopper/sentio" "reflect" "testing" "time" ) func Test_IBKR_QQQ_IsMarketOpened(t *testing.T) { tests := []struct { name string datetime string want bool }{ { name: "1s before open", datetime: "2024-09-05T13:29:59Z", want: false, }, { name: "just opened", datetime: "2024-09-05T13:30:00Z", want: true, }, { name: "Saturday", datetime: "2024-09-07T13:30:00Z", want: false, }, { name: "Sunday", datetime: "2024-09-08T13:30:00Z", want: false, }, { name: "1s before close", datetime: "2024-09-05T18:59:59Z", want: true, }, { name: "just closed", datetime: "2024-09-05T20:00:00Z", want: false, }, { name: "closed", datetime: "2024-09-05T00:30:00Z", want: false, }, } for _, tt := range tests { var ( strategy _ib_qqq dt = sentio.StubClock{} err error ) if dt.Clock, err = time.ParseInLocation(time.RFC3339, tt.datetime, time.UTC); err != nil { t.Errorf("ParseInLocation() = %v", err) continue } strategy = _ib_qqq{clock: dt} t.Run(tt.name, func(t *testing.T) { if got := strategy.IsMarketOpened(); got != tt.want { t.Errorf("IsMarketOpened() = %v, want %v", got, tt.want) } }) } } func Test__ib_qqq_Handle(t *testing.T) { type args struct { proba float64 portfolio sentio.Portfolio time string } tests := []struct { name string args args want []sentio.StrategyOrder }{ { name: "close short position: market reversal", args: args{ proba: 1.00001, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: -10, }, ), time: "2024-08-02T15:04:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderBuy, Ratio: 1, }, }, }, { name: "close long position: market reversal", args: args{ proba: .999, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: 255, }), time: "2024-08-02T15:04:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderSell, Ratio: 1, }, }, }, { name: "close position: market closes", args: args{ proba: 0.00001, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: -10, }, ), time: "2024-08-02T19:34:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderBuy, Ratio: 1, }, }, }, { name: "close position: market closes", args: args{ proba: 1.00201, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: -10, }, ), time: "2024-08-02T19:34:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderBuy, Ratio: 1, }, }, }, { name: "close position: market closes", args: args{ proba: 1.00201, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: 10, }, ), time: "2024-08-02T19:34:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderSell, Ratio: 1, }, }, }, { name: "open position: long", args: args{ proba: 1.00201, time: "2024-08-02T17:34:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderBuy, Ratio: .6, }, }, }, { name: "close LONG position", args: args{ proba: .99, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: 10, }, ), time: "2024-08-02T15:04:05Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderSell, Ratio: 1, }, }, }, { name: "nothing to close or open", args: args{ proba: 1, portfolio: sentio.NewPortfolioStub(), time: "2024-08-02T15:04:05Z", }, }, { name: "nothing to close or open", args: args{ proba: 1, portfolio: nil, time: "2024-08-02T15:04:05Z", }, }, { name: "nothing to close or open", args: args{ proba: 1.002, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "569311092", Size: 100, }, sentio.PositionStub{ Symbol: "521525020", Size: 200, }, ), time: "2024-08-02T15:04:05Z", }, }, { name: "open extra LONG position", args: args{ proba: 1.002000001, portfolio: sentio.NewPortfolioStub( sentio.PositionStub{ Symbol: "320227571", Size: 1, }), time: "2024-08-02T18:30:00Z", }, want: []sentio.StrategyOrder{ { Symbol: "320227571", Action: sentio.OrderBuy, Ratio: .3, }, }, }, } for _, tt := range tests { var ( strategy _ib_qqq dt = sentio.StubClock{} err error ) if dt.Clock, err = time.ParseInLocation(time.RFC3339, tt.args.time, time.UTC); err != nil { t.Errorf("ParseInLocation() = %v", err) continue } strategy = _ib_qqq{clock: dt} t.Run(tt.name, func(t *testing.T) { got := strategy.Handle(tt.args.proba, tt.args.portfolio) if !reflect.DeepEqual(got, tt.want) { t.Errorf("Handle() got = %v, want %v", got, tt.want) } }) } }