Skip to content

Instantly share code, notes, and snippets.

@kirugan
Created March 24, 2023 09:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kirugan/ddbc76d29e2bb1babe1ad13a77c7d663 to your computer and use it in GitHub Desktop.
Save kirugan/ddbc76d29e2bb1babe1ad13a77c7d663 to your computer and use it in GitHub Desktop.
Small script to collect input/output operations in Tinkoff investments
package main
import (
"context"
"crypto/tls"
"flag"
"fmt"
"github.com/davecgh/go-spew/spew"
sdk "github.com/tinkoff/invest-api-go-sdk"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/timestamppb"
"math/rand"
"time"
)
const token = ``
var stats = struct {
Output map[string]int
Input map[string]int
}{
Output: map[string]int{},
Input: map[string]int{},
}
func main() {
SDKInit(token, false)
//Получаем список счетов
accounts, err := GetAccounts()
if err != nil {
panic(err)
}
types := map[sdk.OperationType]int{}
for _, acc := range accounts {
date := acc.GetOpenedDate()
t := ts(date)
ops, err := GetOperations(acc.GetId(), t, time.Now(), "")
if err != nil {
panic(err)
}
fmt.Printf("Operations %d\n", len(ops))
for _, op := range ops {
p := op.Payment
switch op.Type {
case sdk.OperationType_OPERATION_TYPE_OUTPUT:
if op.State != sdk.OperationState_OPERATION_STATE_EXECUTED {
panic(op)
}
if p.Units > 0 {
panic("units positive for output")
}
stats.Output[p.Currency] += abs(int(p.Units))
// fmt.Printf("Вывод %v %v %v\n", p.Units, p.Currency, ts(op.Date))
case sdk.OperationType_OPERATION_TYPE_INPUT:
if op.State != sdk.OperationState_OPERATION_STATE_EXECUTED {
panic(op)
}
if p.Units < 0 {
panic("input is negative")
}
//spew.Dump(op)
stats.Input[p.Currency] += abs(int(p.Units))
default:
types[op.Type]++
}
}
}
spew.Dump(stats)
}
func ts(t *timestamppb.Timestamp) time.Time {
return time.Unix(t.Seconds, int64(t.Nanos))
}
func abs(i int) int {
if i < 0 {
return -i
} else {
return i
}
}
var Instruments sdk.InstrumentsServiceClient
var MarketData sdk.MarketDataServiceClient
var Operations sdk.OperationsServiceClient
var Users sdk.UsersServiceClient
var Orders sdk.OrdersServiceClient
var ctx context.Context
var conn *grpc.ClientConn
var md metadata.MD
const (
address_prod = "invest-public-api.tinkoff.ru:443"
address_sandbox = "sandbox-invest-public-api.tinkoff.ru:443"
)
func SDKInit(token string, use_sandbox bool) {
rand.Seed(time.Now().UnixNano())
flag.Parse()
ctx = context.Background()
addr := address_prod
if use_sandbox {
addr = address_sandbox
}
var err error
conn, err = grpc.Dial(addr,
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})), grpc.WithBlock())
if err != nil {
panic(err)
}
md = metadata.New(map[string]string{"Authorization": "Bearer " + token})
ctx = metadata.NewOutgoingContext(ctx, md)
Instruments = sdk.NewInstrumentsServiceClient(conn)
MarketData = sdk.NewMarketDataServiceClient(conn)
Operations = sdk.NewOperationsServiceClient(conn)
Users = sdk.NewUsersServiceClient(conn)
Orders = sdk.NewOrdersServiceClient(conn)
}
func GetAccounts() ([]*sdk.Account, error) {
var ar sdk.GetAccountsRequest
r, err := Users.GetAccounts(ctx, &ar)
if err != nil {
return nil, err
}
return r.GetAccounts(), nil
}
func GetOperations(AccountId string, from time.Time, to time.Time, figi string) ([]sdk.OperationItem, error) {
var or sdk.OperationsRequest
or.AccountId = AccountId
tsFrom := timestamppb.New(from)
tsTo := timestamppb.New(to)
//or.From = tsFrom
//or.To = tsTo
//or.Figi = figi
//
//r, err := Operations.GetOperations(ctx, &or)
//if err != nil {
// return nil, err
//}
//return r.GetOperations(), nil
var r sdk.GetOperationsByCursorRequest
r.From = tsFrom
r.To = tsTo
r.AccountId = AccountId
r.Limit = 1000
r.OperationTypes = []sdk.OperationType{
sdk.OperationType_OPERATION_TYPE_INPUT,
sdk.OperationType_OPERATION_TYPE_OUTPUT,
}
resp, err := Operations.GetOperationsByCursor(ctx, &r)
if err != nil {
return nil, err
}
var items []sdk.OperationItem
for _, item := range resp.GetItems() {
items = append(items, *item)
}
return items, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment