mirror of
https://github.com/lukewilson2002/autotrader.git
synced 2025-08-02 21:19:33 +00:00
Gave the Series, Frame, and Signals a lot of needed love
This commit is contained in:
110
data.go
110
data.go
@@ -2,13 +2,10 @@ package autotrader
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
df "github.com/rocketlaunchr/dataframe-go"
|
||||
)
|
||||
|
||||
type DataCSVLayout struct {
|
||||
@@ -73,102 +70,51 @@ func DataFrameFromCSVReaderLayout(r io.Reader, layout DataCSVLayout) (*DataFrame
|
||||
data.Series(name).SetName(newName)
|
||||
}
|
||||
|
||||
// err = data.ReorderColumns([]string{"Date", "Open", "High", "Low", "Close", "Volume"})
|
||||
// if err != nil {
|
||||
// return data, err
|
||||
// }
|
||||
|
||||
// TODO: Reverse the dataframe if the latest data is first.
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func DataFrameFromCSVReader(r io.Reader, dateLayout string, readReversed bool) (*DataFrame, error) {
|
||||
csv := csv.NewReader(r)
|
||||
csv.LazyQuotes = true
|
||||
records, err := csv.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(records) < 2 {
|
||||
return nil, errors.New("csv file must have at least 2 rows")
|
||||
}
|
||||
seriesSlice := make([]Series, 0, 12)
|
||||
|
||||
dfSeriesSlice := make([]df.Series, 0, 12)
|
||||
// TODO: change Capacity to Size.
|
||||
initOptions := &df.SeriesInit{Capacity: len(records) - 1}
|
||||
|
||||
// Replace column names with standard ones.
|
||||
for j, val := range records[0] {
|
||||
// Check what type the next row is to determine the type of the series.
|
||||
nextRow := records[1][j]
|
||||
var series df.Series
|
||||
if _, err := strconv.ParseFloat(nextRow, 64); err == nil {
|
||||
series = df.NewSeriesFloat64(val, initOptions)
|
||||
} else if _, err := strconv.ParseInt(nextRow, 10, 64); err == nil {
|
||||
series = df.NewSeriesInt64(val, initOptions)
|
||||
} else if _, err := time.Parse(dateLayout, nextRow); err == nil {
|
||||
series = df.NewSeriesTime(val, initOptions)
|
||||
} else {
|
||||
series = df.NewSeriesString(val, initOptions)
|
||||
// Read the CSV file.
|
||||
for {
|
||||
rec, err := csv.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the series columns and label them.
|
||||
dfSeriesSlice = append(dfSeriesSlice, series)
|
||||
}
|
||||
|
||||
// Set the direction to iterate the records.
|
||||
var startIdx, stopIdx, inc int
|
||||
if readReversed {
|
||||
startIdx = len(records) - 1
|
||||
stopIdx = 0 // Stop before the first row because it contains the column names.
|
||||
inc = -1
|
||||
} else {
|
||||
startIdx = 1 // Skip first row because it contains the column names.
|
||||
stopIdx = len(records)
|
||||
inc = 1
|
||||
}
|
||||
|
||||
for i := startIdx; i != stopIdx; i += inc {
|
||||
rec := records[i]
|
||||
// Create the columns needed.
|
||||
if len(seriesSlice) == 0 {
|
||||
for _, val := range rec {
|
||||
seriesSlice = append(seriesSlice, NewDataSeries(val))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Add rows to the series.
|
||||
for j, val := range rec {
|
||||
series := dfSeriesSlice[j]
|
||||
switch series.Type() {
|
||||
case "float64":
|
||||
val, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
series.Append(nil)
|
||||
} else {
|
||||
series.Append(val)
|
||||
}
|
||||
case "int64":
|
||||
val, err := strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
series.Append(nil)
|
||||
} else {
|
||||
series.Append(val)
|
||||
}
|
||||
case "time":
|
||||
val, err := time.Parse(dateLayout, val)
|
||||
if err != nil {
|
||||
series.Append(nil)
|
||||
} else {
|
||||
series.Append(val)
|
||||
}
|
||||
case "string":
|
||||
series.Append(val)
|
||||
series := seriesSlice[j]
|
||||
if f, err := strconv.ParseFloat(val, 64); err == nil {
|
||||
series.Push(f)
|
||||
} else if t, err := time.Parse(dateLayout, val); err == nil {
|
||||
series.Push(t)
|
||||
} else {
|
||||
series.Push(val)
|
||||
}
|
||||
dfSeriesSlice[j] = series
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we specifically construct the DataFrame at the end of the function because it likes to set
|
||||
// state like number of rows and columns at initialization and won't let you change it later.
|
||||
seriesSlice := make([]Series, len(dfSeriesSlice))
|
||||
for i, series := range dfSeriesSlice {
|
||||
seriesSlice[i] = NewDataSeries(series)
|
||||
// Reverse the series if needed.
|
||||
if readReversed {
|
||||
for _, series := range seriesSlice {
|
||||
series.Reverse()
|
||||
}
|
||||
}
|
||||
|
||||
return NewDataFrame(seriesSlice...), nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user