Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repository factory is added. #206

Merged
merged 1 commit into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,12 @@ The [Sync function]() facilitates the synchronization of assets between designat
The `indicator-sync` command line tool also offers the capability of synchronizing data between the Tiingo Repository and the File System Repository. To illustrate its usage, consider the following example command:

```bash
$ indicator-sync -key $TIINGO_KEY -target /home/user/assets -days 30
$ indicator-sync \
-source-name tiingo \
-source-config $TIINGO_KEY \
-target-name filesystem \
-target-config /home/user/assets \
-days 30
```

This command effectively retrieves the most recent snapshots for assets residing within the `/home/user/assets` directory from the Tiingo Repository. In the event that the local asset file is devoid of content, it automatically extends its reach to synchronize 30 days' worth of snapshots, ensuring a comprehensive and up-to-date repository.
Expand All @@ -201,7 +206,11 @@ if err != nil {
The `indicator-backtest` command line tool empowers users to conduct comprehensive backtesting of assets residing within a specified repository. This capability encompasses the application of all currently recognized strategies, culminating in the generation of detailed reports within a designated output directory.

```bash
$ indicator-backtest -repository /home/user/assets -output /home/user/reports -workers 1
$ indicator-backtest \
-source-name filesystem \
-source-config /home/user/assets \
-output /home/user/reports \
-workers 1
```

Usage
Expand Down
45 changes: 45 additions & 0 deletions asset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The information provided on this project is strictly for informational purposes

- [Constants](<#constants>)
- [Variables](<#variables>)
- [func RegisterRepositoryBuilder\(name string, builder RepositoryBuilderFunc\)](<#RegisterRepositoryBuilder>)
- [func SnapshotsAsClosings\(snapshots \<\-chan \*Snapshot\) \<\-chan float64](<#SnapshotsAsClosings>)
- [func SnapshotsAsDates\(snapshots \<\-chan \*Snapshot\) \<\-chan time.Time](<#SnapshotsAsDates>)
- [func SnapshotsAsHighs\(snapshots \<\-chan \*Snapshot\) \<\-chan float64](<#SnapshotsAsHighs>)
Expand All @@ -47,6 +48,8 @@ The information provided on this project is strictly for informational purposes
- [func \(r \*InMemoryRepository\) GetSince\(name string, date time.Time\) \(\<\-chan \*Snapshot, error\)](<#InMemoryRepository.GetSince>)
- [func \(r \*InMemoryRepository\) LastDate\(name string\) \(time.Time, error\)](<#InMemoryRepository.LastDate>)
- [type Repository](<#Repository>)
- [func NewRepository\(name, config string\) \(Repository, error\)](<#NewRepository>)
- [type RepositoryBuilderFunc](<#RepositoryBuilderFunc>)
- [type Snapshot](<#Snapshot>)
- [type Sync](<#Sync>)
- [func NewSync\(\) \*Sync](<#NewSync>)
Expand All @@ -65,6 +68,21 @@ The information provided on this project is strictly for informational purposes

## Constants

<a name="InMemoryRepositoryBuilderName"></a>

```go
const (
// InMemoryRepositoryBuilderName is the name for the in memory repository builder.
InMemoryRepositoryBuilderName = "memory"

// FileSystemRepositoryBuilderName is the name for the file system repository builder.
FileSystemRepositoryBuilderName = "filesystem"

// TiingoRepositoryBuilderName is the name of the Tiingo repository builder.
TiingoRepositoryBuilderName = "tiingo"
)
```

<a name="DefaultSyncWorkers"></a>

```go
Expand All @@ -91,6 +109,15 @@ var ErrRepositoryAssetEmpty = errors.New("asset empty")
var ErrRepositoryAssetNotFound = errors.New("asset is not found")
```

<a name="RegisterRepositoryBuilder"></a>
## func [RegisterRepositoryBuilder](<https://github.com/cinar/indicator/blob/master/asset/repository_factory.go#L33>)

```go
func RegisterRepositoryBuilder(name string, builder RepositoryBuilderFunc)
```

RegisterRepositoryBuilder registers the given builder.

<a name="SnapshotsAsClosings"></a>
## func [SnapshotsAsClosings](<https://github.com/cinar/indicator/blob/master/asset/snapshot.go#L79>)

Expand Down Expand Up @@ -303,6 +330,24 @@ type Repository interface {
}
```

<a name="NewRepository"></a>
### func [NewRepository](<https://github.com/cinar/indicator/blob/master/asset/repository_factory.go#L38>)

```go
func NewRepository(name, config string) (Repository, error)
```

NewRepository builds a new repository by the given name type and the configuration.

<a name="RepositoryBuilderFunc"></a>
## type [RepositoryBuilderFunc](<https://github.com/cinar/indicator/blob/master/asset/repository_factory.go#L23>)

RepositoryBuilderFunc defines a function to build a new repository using the given configuration parameter.

```go
type RepositoryBuilderFunc func(config string) (Repository, error)
```

<a name="Snapshot"></a>
## type [Snapshot](<https://github.com/cinar/indicator/blob/master/asset/snapshot.go#L15-L38>)

Expand Down
60 changes: 60 additions & 0 deletions asset/repository_factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2021-2024 Onur Cinar.
// The source code is provided under GNU AGPLv3 License.
// https://github.com/cinar/indicator

package asset

import (
"fmt"
)

const (
// InMemoryRepositoryBuilderName is the name for the in memory repository builder.
InMemoryRepositoryBuilderName = "memory"

// FileSystemRepositoryBuilderName is the name for the file system repository builder.
FileSystemRepositoryBuilderName = "filesystem"

// TiingoRepositoryBuilderName is the name of the Tiingo repository builder.
TiingoRepositoryBuilderName = "tiingo"
)

// RepositoryBuilderFunc defines a function to build a new repository using the given configuration parameter.
type RepositoryBuilderFunc func(config string) (Repository, error)

// repositoryBuilders provides mapping for the repository builders.
var repositoryBuilders = map[string]RepositoryBuilderFunc{
InMemoryRepositoryBuilderName: inMemoryRepositoryBuilder,
FileSystemRepositoryBuilderName: fileSystemRepositoryBuilder,
TiingoRepositoryBuilderName: tiingoRepositoryBuilder,
}

// RegisterRepositoryBuilder registers the given builder.
func RegisterRepositoryBuilder(name string, builder RepositoryBuilderFunc) {
repositoryBuilders[name] = builder
}

// NewRepository builds a new repository by the given name type and the configuration.
func NewRepository(name, config string) (Repository, error) {
builder, ok := repositoryBuilders[name]
if !ok {
return nil, fmt.Errorf("unknown repository: %s", name)
}

return builder(config)
}

// inMemoryRepositoryBuilder builds a new in memory repository instance.
func inMemoryRepositoryBuilder(_ string) (Repository, error) {
return NewInMemoryRepository(), nil
}

// fileSystemRepositoryBuilder builds a new file system repository instance.
func fileSystemRepositoryBuilder(config string) (Repository, error) {
return NewFileSystemRepository(config), nil
}

// tiingoRepositoryBuilder builds a new Tiingo repository instance.
func tiingoRepositoryBuilder(config string) (Repository, error) {
return NewTiingoRepository(config), nil
}
47 changes: 47 additions & 0 deletions asset/repository_factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2021-2024 Onur Cinar.
// The source code is provided under GNU AGPLv3 License.
// https://github.com/cinar/indicator

package asset_test

import (
"testing"

"github.com/cinar/indicator/v2/asset"
)

func TestNewRepositoryMemory(t *testing.T) {
repository, err := asset.NewRepository(asset.InMemoryRepositoryBuilderName, "")
if err != nil {
t.Fatal(err)
}

_, ok := repository.(*asset.InMemoryRepository)
if !ok {
t.Fatalf("repository not correct type: %T", repository)
}
}

func TestNewRepositoryFileSystem(t *testing.T) {
repository, err := asset.NewRepository(asset.FileSystemRepositoryBuilderName, "testdata")
if err != nil {
t.Fatal(err)
}

_, ok := repository.(*asset.FileSystemRepository)
if !ok {
t.Fatalf("repository not correct type: %T", repository)
}
}

func TestNewTiingoRepository(t *testing.T) {
repository, err := asset.NewRepository(asset.TiingoRepositoryBuilderName, "1234")
if err != nil {
t.Fatal(err)
}

_, ok := repository.(*asset.TiingoRepository)
if !ok {
t.Fatalf("repository not correct type: %T", repository)
}
}
19 changes: 11 additions & 8 deletions cmd/indicator-backtest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import (
)

func main() {
var repositoryDir string
var sourceName string
var sourceConfig string
var outputDir string
var workers int
var lastDays int
Expand All @@ -36,7 +37,8 @@ func main() {
fmt.Fprintln(os.Stderr, "https://github.com/cinar/indicator")
fmt.Fprintln(os.Stderr)

flag.StringVar(&repositoryDir, "repository", ".", "file system repository directory")
flag.StringVar(&sourceName, "source-name", "filesystem", "source repository type")
flag.StringVar(&sourceConfig, "source-config", "", "source repository config")
flag.StringVar(&outputDir, "output", ".", "output directory")
flag.IntVar(&workers, "workers", strategy.DefaultBacktestWorkers, "number of concurrent workers")
flag.IntVar(&lastDays, "last", strategy.DefaultLastDays, "number of days to do backtest")
Expand All @@ -46,11 +48,12 @@ func main() {
flag.StringVar(&dateFormat, "date-format", helper.DefaultReportDateFormat, "date format to use")
flag.Parse()

flag.Parse()

repository := asset.NewFileSystemRepository(repositoryDir)
source, err := asset.NewRepository(sourceName, sourceConfig)
if err != nil {
log.Fatalf("unable to initialize source: %v", err)
}

backtest := strategy.NewBacktest(repository, outputDir)
backtest := strategy.NewBacktest(source, outputDir)
backtest.Workers = workers
backtest.LastDays = lastDays
backtest.WriteStrategyReports = writeStrategyRerpots
Expand All @@ -70,8 +73,8 @@ func main() {
backtest.Strategies = append(backtest.Strategies, strategy.AllAndStrategies(backtest.Strategies)...)
}

err := backtest.Run()
err = backtest.Run()
if err != nil {
log.Fatal(err)
log.Fatalf("unable to run backtest: %v", err)
}
}
37 changes: 26 additions & 11 deletions cmd/indicator-sync/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (
)

func main() {
var tiingoKey string
var targetBase string
var sourceName string
var sourceConfig string
var targetName string
var targetConfig string
var minusDays int
var workers int
var delay int
Expand All @@ -28,29 +30,42 @@ func main() {
fmt.Fprintln(os.Stderr, "https://github.com/cinar/indicator")
fmt.Fprintln(os.Stderr)

flag.StringVar(&tiingoKey, "key", "", "tiingo service api key")
flag.StringVar(&targetBase, "target", ".", "target repository base directory")
flag.StringVar(&sourceName, "source-name", "tiingo", "source repository type")
flag.StringVar(&sourceConfig, "source-config", "", "source repository config")
flag.StringVar(&targetName, "target-name", "filesystem", "target repository type")
flag.StringVar(&targetConfig, "target-config", "", "target repository config")
flag.IntVar(&minusDays, "days", 0, "lookback period in days for the new assets")
flag.IntVar(&workers, "workers", asset.DefaultSyncWorkers, "number of concurrent workers")
flag.IntVar(&delay, "delay", asset.DefaultSyncDelay, "delay between each get")
flag.Parse()

if tiingoKey == "" {
log.Fatal("Tiingo API key required")
source, err := asset.NewRepository(sourceName, sourceConfig)
if err != nil {
log.Fatalf("unable to initialize source: %v", err)
}

target, err := asset.NewRepository(targetName, targetConfig)
if err != nil {
log.Fatalf("unable to initialize target: %v", err)
}

defaultStartDate := time.Now().AddDate(0, 0, -minusDays)

source := asset.NewTiingoRepository(tiingoKey)
target := asset.NewFileSystemRepository(targetBase)
assets := flag.Args()
if len(assets) == 0 {
assets, err = source.Assets()
if err != nil {
log.Fatalf("unable to get assets: %v", err)
}
}

sync := asset.NewSync()
sync.Workers = workers
sync.Delay = delay
sync.Assets = flag.Args()
sync.Assets = assets

err := sync.Run(source, target, defaultStartDate)
err = sync.Run(source, target, defaultStartDate)
if err != nil {
log.Fatal(err)
log.Fatalf("unable to sync repositories: %v", err)
}
}
4 changes: 2 additions & 2 deletions strategy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const (
```

<a name="ActionSources"></a>
## func [ActionSources](<https://github.com/cinar/indicator/blob/master/strategy/strategy.go#L67>)
## func [ActionSources](<https://github.com/cinar/indicator/blob/master/strategy/strategy.go#L62>)

```go
func ActionSources(strategies []Strategy, snapshots <-chan *asset.Snapshot) []<-chan Action
Expand Down Expand Up @@ -555,7 +555,7 @@ func AllSplitStrategies(strategies []Strategy) []Strategy
AllSplitStrategies performs a cartesian product operation on the given strategies, resulting in a collection containing all split strategies formed by combining individual buy and sell strategies.

<a name="AllStrategies"></a>
### func [AllStrategies](<https://github.com/cinar/indicator/blob/master/strategy/strategy.go#L59>)
### func [AllStrategies](<https://github.com/cinar/indicator/blob/master/strategy/strategy.go#L54>)

```go
func AllStrategies() []Strategy
Expand Down
Loading