From c109e68a7ae00916ca431bcaf3425941b07ff474 Mon Sep 17 00:00:00 2001 From: Natercio Moniz Date: Fri, 7 Nov 2025 13:04:40 +0000 Subject: [PATCH] initial processing of trading212 csv statement --- main.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/main.go b/main.go index da29a2c..8352b79 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,75 @@ package main +import ( + "container/list" + "encoding/csv" + "errors" + "fmt" + "io" + "log/slog" + "os" + "strings" +) + func main() { + err := run() + if err != nil { + slog.Error("fatal error", slog.Any("err", err)) + } } + +func run() error { + f, err := os.Open("test.csv") + if err != nil { + return fmt.Errorf("open statement: %w", err) + } + + r := csv.NewReader(f) + + assets := make(map[string]*list.List) + for { + record, err := r.Read() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return fmt.Errorf("read statement record: %w", err) + } + + switch strings.ToLower(record[0]) { + case "market buy": + lst, ok := assets[record[2]] + if !ok { + lst = list.New() + assets[record[2]] = lst + } + lst.PushBack(record[12]) + + case "market sell": + lst, ok := assets[record[2]] + if !ok { + return ErrSellWithoutBuy + } + + first := lst.Front() + if first == nil { + return ErrSellWithoutBuy + } + + slog.Info("Realised PnL", slog.Any("record", record)) + + case "action", "stock split open", "stock split close": + // ignored + + default: + return fmt.Errorf("unhandled record: %s", record[0]) + } + + } + + slog.Info("Finish processing statement", slog.Any("assets_count", len(assets))) + + return nil +} + +var ErrSellWithoutBuy = fmt.Errorf("found sell without bought volume")