separate trading212 logic
This commit is contained in:
108
internal/trading212/record.go
Normal file
108
internal/trading212/record.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package trading212
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.naterciomoniz.net/applications/broker2anexoj/internal"
|
||||
)
|
||||
|
||||
type Record struct {
|
||||
symbol string
|
||||
direction internal.Direction
|
||||
quantity *big.Float
|
||||
price *big.Float
|
||||
timestamp time.Time
|
||||
}
|
||||
|
||||
func (r Record) Symbol() string {
|
||||
return r.symbol
|
||||
}
|
||||
|
||||
func (r Record) Direction() internal.Direction {
|
||||
return r.direction
|
||||
}
|
||||
|
||||
func (r Record) Quantity() *big.Float {
|
||||
return r.quantity
|
||||
}
|
||||
|
||||
func (r Record) Price() *big.Float {
|
||||
return r.price
|
||||
}
|
||||
|
||||
func (r Record) Timestamp() time.Time {
|
||||
return r.timestamp
|
||||
}
|
||||
|
||||
type RecordReader struct {
|
||||
reader *csv.Reader
|
||||
}
|
||||
|
||||
func NewRecordReader(r io.Reader) *RecordReader {
|
||||
return &RecordReader{
|
||||
reader: csv.NewReader(r),
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
MarketBuy = "market buy"
|
||||
MarketSell = "market sell"
|
||||
LimitBuy = "limit buy"
|
||||
LimitSell = "limit sell"
|
||||
)
|
||||
|
||||
func (rr RecordReader) ReadRecord() (Record, error) {
|
||||
for {
|
||||
raw, err := rr.reader.Read()
|
||||
if err != nil {
|
||||
return Record{}, fmt.Errorf("read record: %w", err)
|
||||
}
|
||||
|
||||
var dir internal.Direction
|
||||
switch strings.ToLower(raw[0]) {
|
||||
case MarketBuy, LimitBuy:
|
||||
dir = internal.DirectionBuy
|
||||
case MarketSell, LimitSell:
|
||||
dir = internal.DirectionSell
|
||||
case "action", "stock split open", "stock split close":
|
||||
continue
|
||||
default:
|
||||
return Record{}, fmt.Errorf("parse record type: %s", raw[0])
|
||||
}
|
||||
|
||||
qant, err := parseDecimal(raw[6])
|
||||
if err != nil {
|
||||
return Record{}, fmt.Errorf("parse record quantity: %w", err)
|
||||
}
|
||||
|
||||
price, err := parseDecimal(raw[7])
|
||||
if err != nil {
|
||||
return Record{}, fmt.Errorf("parse record price: %w", err)
|
||||
}
|
||||
|
||||
ts, err := time.Parse(time.DateTime, raw[1])
|
||||
if err != nil {
|
||||
return Record{}, fmt.Errorf("parse record timestamp: %w", err)
|
||||
}
|
||||
|
||||
return Record{
|
||||
symbol: raw[2],
|
||||
direction: dir,
|
||||
quantity: qant,
|
||||
price: price,
|
||||
timestamp: ts,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// parseFloat attempts to parse a string using a standard precision and rounding mode.
|
||||
// Using this function helps avoid issues around converting values due to sligh parameter changes.
|
||||
func parseDecimal(s string) (*big.Float, error) {
|
||||
f, _, err := big.ParseFloat(s, 10, 128, big.ToZero)
|
||||
return f, err
|
||||
}
|
||||
Reference in New Issue
Block a user