I'm new to Go, and looking to create my own algo trading strategy backtesting library, an area I'm well experienced in with Python, to help learn the language.
I have a 5 minute OHLCV SPY5min.csv
dataset, the head of which looks like this:
I use this code to read in the dataset from the file, converting everything to a list of lists of values:
package main
import (
"encoding/csv"
"log"
"os"
"fmt"
)
func ReadCsvFile(filePath string) [][]string {
f, err := os.Open(filePath)
if err != nil {
log.Fatal("Unable to read input file " filePath, err)
}
defer f.Close()
csvReader := csv.NewReader(f)
records, err := csvReader.ReadAll()
if err != nil {
log.Fatal("Unable to parse file as CSV for " filePath, err)
}
return records
}
func main() {
records := ReadCsvFile("./SPY5min.csv")
fmt.Println(records)
}
This returns a list of lists of string values. Cool. Now what I want to do is replicate a Pandas Dataframe like object, or perhaps separate each "column" into their own separate arrays/slices if that's easier, not sure yet.
Once that's done, I need a way to convert the strings of datetimes to actual datetime objects that I can run comparisons and loc
's on. Can someone point me in the right direction?
My naive approach (pseudo) would be to:
- Declare 6 array variables (datetime, open, high, low, close, volume) of
len(records)
in size - Iterate over the
records
list of lists - Insert each value into the current
i
of their respective arrays - Once iteration is done, mass convert the values in the
datetime
array to values of datetime objects?
Wondering if this is really the best way of doing this, or if there's a faster way than O(n)
iteration?
CodePudding user response:
You asked, "Once that's done, I need a way to convert the strings of datetimes to actual datetime objects ...". I recently answered a similar question here: https://stackoverflow.com/a/74491722/5739452
Your timestamp looks like this: "2022-11-08 4:00"
. The time
package contains parsing and other manipulation functions. The key detail is knowing the conventions for the layout parser format. Each element of a time is recognized as a specific number. The year is 2006
, the month is 11
etc.
So, for your purpose something like this should work:
package main
import (
"fmt"
"time"
)
func main() {
t := "2022-11-08 4:00"
const layout = "2006-01-02 15:04"
x, err := time.Parse(layout, t)
fmt.Println(x, err)
}
CodePudding user response:
You could use a method based approach, like this:
package trading
import (
"encoding/csv"
"io"
"strconv"
"time"
)
type record []string
func records(r io.Reader) ([]record, error) {
var recs []record
raw := csv.NewReader(r)
for {
rec, err := raw.Read()
if err == io.EOF {
return recs, nil
} else if err != nil {
return nil, err
}
recs = append(recs, rec)
}
}
func (r record) time() (time.Time, error) {
return time.Parse("2006-01-02 15:04", r[0])
}
func (r record) open() (float64, error) {
return strconv.ParseFloat(r[1], 64)
}