76 lines
1.3 KiB
Go
76 lines
1.3 KiB
Go
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")
|