|
@@ -0,0 +1,295 @@
|
|
|
|
+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)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+}
|