Skip to content

Feat: Implement CheckPatternBasic Algorithm #218

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
111 changes: 111 additions & 0 deletions internal/algorithm/checkpatternbasic/example.go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파일명을 example이 아니라 내용물이 잘 드러나도록 수정해주시기 바랍니다.
ex)model

Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package checkpatternbasic

import "math"

type Status int

const (
StatusUndefined Status = iota
StatusDecreasing
StatusIncreasing
)

type ChangeStatus int

const (
ChangeStatusUnchanged ChangeStatus = iota
ChangeStatusDecreasing
ChangeStatusIncreasing
)

type TradeEvent int

const (
TradeEventHold TradeEvent = iota
TradeEventBuy
TradeEventSell
)

func (m *Model) calculateChangeStatus(value float64) ChangeStatus {
if m.prvValue < value && (value-m.currMin) >= m.threshold {
return ChangeStatusIncreasing
}

if m.prvValue > value && (m.currMax-value) >= m.threshold {
return ChangeStatusDecreasing
}

return ChangeStatusUnchanged
}

type Model struct {
Status Status
currMin float64
currMax float64
prvValue float64
threshold float64
}

func NewModel(threshold float64) *Model {
return &Model{
Status: StatusUndefined,
currMin: math.MaxFloat64,
currMax: -math.MaxFloat64,
prvValue: 0.0,
threshold: threshold,
}
}

func (m *Model) OnEvent(value float64) (float64, TradeEvent) {
m.currMax = max(m.currMax, value)
m.currMin = min(m.currMin, value)

var event TradeEvent = TradeEventHold

switch m.Status {

case StatusIncreasing:
switch m.calculateChangeStatus(value) {
case ChangeStatusDecreasing:
m.Status = StatusDecreasing
event = TradeEventSell
m.currMin = value
}

case StatusDecreasing:
switch m.calculateChangeStatus(value) {
case ChangeStatusIncreasing:
m.Status = StatusIncreasing
event = TradeEventBuy
m.currMax = value
}

case StatusUndefined:
switch m.calculateChangeStatus(value) {
case ChangeStatusIncreasing:
m.Status = StatusIncreasing
event = TradeEventBuy
case ChangeStatusDecreasing:
m.Status = StatusDecreasing
event = TradeEventSell
}
}

m.prvValue = value

var power float64
if m.currMax == m.currMin {
power = 0
return power, event
}

switch m.Status {
case StatusIncreasing:
power = value - m.currMax
case StatusDecreasing:
power = value - m.currMin
case StatusUndefined:
power = 0
}
return power, event
}
81 changes: 81 additions & 0 deletions internal/algorithm/checkpatternbasic/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package checkpatternbasic

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestXxx(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 코드 이름에 테스트 대상이 명확히 드러나도록 수정해주세요

Suggested change
func TestXxx(t *testing.T) {
func TestModel(t *testing.T)

type outputFormat struct {
rate float64
event TradeEvent
}

// Arrange
var tests = []struct {
model *Model
input []float64
output []outputFormat
}{
{
NewModel(3),
[]float64{0, 1, 2, 4, 5},
[]outputFormat{
{0, TradeEventHold},
{0, TradeEventHold},
{0, TradeEventHold},
{0, TradeEventBuy},
{0, TradeEventHold},
},
},
{
NewModel(2.5),
[]float64{5, 4, 3, 2, 1},
[]outputFormat{
{0, TradeEventHold},
{0, TradeEventHold},
{0, TradeEventHold},
{0, TradeEventSell},
{0, TradeEventHold},
},
},
{
NewModel(3),
[]float64{1, 3, 5, 4, 2},
[]outputFormat{
{0, TradeEventHold},
{0, TradeEventHold},
{0, TradeEventBuy},
{-1, TradeEventHold},
{0, TradeEventSell},
},
},
{
NewModel(5),
[]float64{1, 3, 7, 5, 2, 3, 4, 1},
[]outputFormat{
{0, TradeEventHold},
{0, TradeEventHold},
{0, TradeEventBuy},
{-2, TradeEventHold},
{0, TradeEventSell},
{1, TradeEventHold},
{2, TradeEventHold},
{0, TradeEventHold},
},
},
}

for i, v := range tests {
for j, value := range v.input {
// Act
rate, event := v.model.OnEvent(value)

// Assert
assert.Equal(t, v.output[j].rate, rate, "Test case %d, input %d", i, j)
assert.Equal(t, v.output[j].event, event, "Test case %d, input %d", i, j)
}
}

}
3 changes: 0 additions & 3 deletions internal/algorithm/example.go

This file was deleted.

70 changes: 70 additions & 0 deletions internal/job/analyzer/checkpatternbasic.go
Copy link
Contributor

@lsjtop10 lsjtop10 Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Job 구현이 깔끔하고 좋네요. 앞으로 새로운 job을 추가하실 때도 이처럼 하시면 됩니다.

Copy link
Contributor

@lsjtop10 lsjtop10 Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 알고리즘을 테스트 하셨지만, job이 데이터를 잘 처리하는지 보기 위해 간단한 테스트만 추가해주세요. 여기 테스트는 알고리즘 테스트케이스만큼 많을 필요는 없습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package analyzer

import (
"github.com/Goboolean/core-system.worker/internal/algorithm/checkpatternbasic"
"github.com/Goboolean/core-system.worker/internal/job"
"github.com/Goboolean/core-system.worker/internal/model"
"github.com/Goboolean/core-system.worker/internal/util/chanutil"
)

type CheckPatternBasic struct {
in job.DataChan
out job.DataChan

model checkpatternbasic.Model
}

func NewCheckPatternBasic(parmas *job.UserParams) (*CheckPatternBasic, error) {
instance := &CheckPatternBasic{
out: make(job.DataChan),
}

return instance, nil
}

func (s *CheckPatternBasic) Execute() error {
defer close(s.out)
defer func() {
go chanutil.DummyChannelConsumer(s.in)
}()

for v := range s.in {
t := v.Time
stock := v.Data.(*model.StockAggregate)

indicator, action := s.model.OnEvent(float64(stock.Close))

switch action {
case checkpatternbasic.TradeEventBuy:
s.out <- model.Packet{
Time: t,
Data: &model.TradeCommand{
Action: model.Buy,
ProportionPercent: 0,
},
}
case checkpatternbasic.TradeEventSell:
s.out <- model.Packet{
Time: t,
Data: &model.TradeCommand{
Action: model.Sell,
ProportionPercent: 0,
},
}
}

s.out <- model.Packet{
Time: t,
Data: indicator,
}
}
return nil
}

func (s *CheckPatternBasic) SetInput(in job.DataChan) {
s.in = in
}

func (s *CheckPatternBasic) Output() job.DataChan {
return s.out
}
51 changes: 0 additions & 51 deletions internal/job/analyzer/example.go

This file was deleted.

Loading