-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(indicators): create rsi indicator
- Loading branch information
1 parent
eeac38a
commit 8b93541
Showing
6 changed files
with
532 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
package calculator | ||
|
||
// | ||
//import ( | ||
// "context" | ||
// "github.com/google/uuid" | ||
// chipmunkApi "github.com/h-varmazyar/Gate/services/chipmunk/api/proto" | ||
// "github.com/h-varmazyar/Gate/services/chipmunk/internal/pkg/buffer" | ||
// "github.com/h-varmazyar/Gate/services/chipmunk/internal/pkg/entity" | ||
// log "github.com/sirupsen/logrus" | ||
// "math" | ||
//) | ||
// | ||
//type BollingerBands struct { | ||
// id uuid.UUID | ||
// entity.BollingerBandsConfigs | ||
// sma *movingAverage | ||
//} | ||
// | ||
//type BollingerBandsValue struct { | ||
// UpperBand float64 | ||
// LowerBand float64 | ||
// MA float64 | ||
//} | ||
// | ||
//func NewBollingerBands(configs *entity.BollingerBandsConfigs) (*BollingerBands, error) { | ||
// if err := validateBollingerBandsConfigs(configs); err != nil { | ||
// return nil, err | ||
// } | ||
// return &BollingerBands{ | ||
// id: id, | ||
// BollingerBandsConfigs: *configs, | ||
// sma: &movingAverage{ | ||
// id: id, | ||
// MovingAverageConfigs: entity.MovingAverageConfigs{ | ||
// Length: configs.Length, | ||
// Source: configs.Source, | ||
// }, | ||
// }, | ||
// }, nil | ||
//} | ||
// | ||
//func (conf *BollingerBands) Calculate(ctx context.Context, candles []*chipmunkApi.Candle, values []*BollingerBandsValue) error { | ||
// _, err := conf.sma.sma(candles) | ||
// if err != nil { | ||
// return err | ||
// } | ||
// for i := conf.Length - 1; i < len(candles); i++ { | ||
// conf.calculateBB(candles[1+i-conf.Length : i+1]) | ||
// //variance := float64(0) | ||
// //ma := rateLimiters[i].MovingAverages[conf.id].Simple | ||
// //for j := 1 + i - conf.Length; j <= i; j++ { | ||
// // sum := float64(0) | ||
// // switch conf.Source { | ||
// // case chipmunkApi.Source_Open: | ||
// // sum = rateLimiters[j].Open | ||
// // case chipmunkApi.Source_High: | ||
// // sum = rateLimiters[j].High | ||
// // case chipmunkApi.Source_Low: | ||
// // sum = rateLimiters[j].Low | ||
// // case chipmunkApi.Source_Close: | ||
// // sum = rateLimiters[j].Close | ||
// // case chipmunkApi.Source_OHLC4: | ||
// // sum = (rateLimiters[j].Open + rateLimiters[j].High + rateLimiters[j].Low + rateLimiters[j].Close) / 4 | ||
// // case chipmunkApi.Source_HLC3: | ||
// // sum = (rateLimiters[j].Low + rateLimiters[j].High + rateLimiters[j].Close) / 3 | ||
// // case chipmunkApi.Source_HL2: | ||
// // sum = (rateLimiters[j].Low + rateLimiters[j].High) / 2 | ||
// // } | ||
// // variance += math.Pow(ma-sum, 2) | ||
// //} | ||
// //variance /= float64(conf.Length) | ||
// // | ||
// //if rateLimiters[i] == nil { | ||
// // log.Errorf("nil candle") | ||
// //} | ||
// // | ||
// //rateLimiters[i].BollingerBands[conf.id] = &entity.BollingerBandsValue{ | ||
// // UpperBand: ma + float64(conf.Deviation)*math.Sqrt(variance), | ||
// // LowerBand: ma - float64(conf.Deviation)*math.Sqrt(variance), | ||
// // MA: ma, | ||
// //} | ||
// } | ||
// return nil | ||
//} | ||
// | ||
//func (conf *BollingerBands) UpdateLast(ctx context.Context, candles []*entity.Candle, value *BollingerBandsValue) { | ||
// if len(candles) == 0 { | ||
// return | ||
// } | ||
// first := candles[0] | ||
// start := buffer.CandleBuffer.Before(first.MarketID.String(), first.ResolutionID.String(), first.Time, conf.Length-1) | ||
// if len(start) == 0 { | ||
// return | ||
// } | ||
// | ||
// internalCandles := append(start, candles...) | ||
// | ||
// _, err := conf.sma.sma(internalCandles) | ||
// if err != nil { | ||
// log.WithError(err).Error("failed to calculate sma for bollinger bands") | ||
// return | ||
// } | ||
// | ||
// for i := conf.Length - 1; i < len(internalCandles); i++ { | ||
// conf.calculateBB(candles[1+i-conf.Length : i+1]) | ||
// //variance := float64(0) | ||
// //ma := internalCandles[i].MovingAverages[conf.id].Simple | ||
// //for j := 1 + i - conf.Length; j <= i; j++ { | ||
// // sum := float64(0) | ||
// // switch conf.Source { | ||
// // case chipmunkApi.Source_Open: | ||
// // sum = rateLimiters[j].Open | ||
// // case chipmunkApi.Source_High: | ||
// // sum = rateLimiters[j].High | ||
// // case chipmunkApi.Source_Low: | ||
// // sum = rateLimiters[j].Low | ||
// // case chipmunkApi.Source_Close: | ||
// // sum = rateLimiters[j].Close | ||
// // case chipmunkApi.Source_OHLC4: | ||
// // sum = (rateLimiters[j].Open + rateLimiters[j].High + rateLimiters[j].Low + rateLimiters[j].Close) / 4 | ||
// // case chipmunkApi.Source_HLC3: | ||
// // sum = (rateLimiters[j].Low + rateLimiters[j].High + rateLimiters[j].Close) / 3 | ||
// // case chipmunkApi.Source_HL2: | ||
// // sum = (rateLimiters[j].Low + rateLimiters[j].High) / 2 | ||
// // } | ||
// // variance += math.Pow(ma-sum, 2) | ||
// //} | ||
// //variance /= float64(conf.Length) | ||
// // | ||
// //rateLimiters[i].BollingerBands[conf.id] = &entity.BollingerBandsValue{ | ||
// // UpperBand: ma + float64(conf.Deviation)*math.Sqrt(variance), | ||
// // LowerBand: ma - float64(conf.Deviation)*math.Sqrt(variance), | ||
// // MA: ma, | ||
// //} | ||
// } | ||
//} | ||
// | ||
//func (conf *BollingerBands) calculateBB(candles []*entity.Candle) { | ||
// variance := float64(0) | ||
// index := len(candles) - 1 | ||
// ma := candles[index].MovingAverages[conf.id].Simple | ||
// for j := 0; j < len(candles); j++ { | ||
// sum := float64(0) | ||
// switch conf.Source { | ||
// case chipmunkApi.Source_Open: | ||
// sum = candles[j].Open | ||
// case chipmunkApi.Source_High: | ||
// sum = candles[j].High | ||
// case chipmunkApi.Source_Low: | ||
// sum = candles[j].Low | ||
// case chipmunkApi.Source_Close: | ||
// sum = candles[j].Close | ||
// case chipmunkApi.Source_OHLC4: | ||
// sum = (candles[j].Open + candles[j].High + candles[j].Low + candles[j].Close) / 4 | ||
// case chipmunkApi.Source_HLC3: | ||
// sum = (candles[j].Low + candles[j].High + candles[j].Close) / 3 | ||
// case chipmunkApi.Source_HL2: | ||
// sum = (candles[j].Low + candles[j].High) / 2 | ||
// } | ||
// variance += math.Pow(ma-sum, 2) | ||
// } | ||
// variance /= float64(conf.Length) | ||
// | ||
// candles[index].BollingerBands[conf.id] = &entity.BollingerBandsValue{ | ||
// UpperBand: ma + float64(conf.Deviation)*math.Sqrt(variance), | ||
// LowerBand: ma - float64(conf.Deviation)*math.Sqrt(variance), | ||
// MA: ma, | ||
// } | ||
//} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package calculator | ||
|
||
import chipmunkAPI "github.com/h-varmazyar/Gate/services/chipmunk/api/proto" | ||
|
||
func cloneCandle(from *chipmunkAPI.Candle) *chipmunkAPI.Candle { | ||
if from == nil { | ||
return nil | ||
} | ||
|
||
return &chipmunkAPI.Candle{ | ||
UpdatedAt: from.UpdatedAt, | ||
CreatedAt: from.CreatedAt, | ||
Volume: from.Volume, | ||
Amount: from.Amount, | ||
Close: from.Close, | ||
Open: from.Open, | ||
Time: from.Time, | ||
High: from.High, | ||
Low: from.Low, | ||
ID: from.ID, | ||
MarketID: from.MarketID, | ||
ResolutionID: from.ResolutionID, | ||
} | ||
} | ||
|
||
func cloneCandles(from []*chipmunkAPI.Candle) []*chipmunkAPI.Candle { | ||
if from == nil { | ||
return nil | ||
} | ||
|
||
to := make([]*chipmunkAPI.Candle, len(from)) | ||
for i, candle := range from { | ||
to[i] = cloneCandle(candle) | ||
} | ||
return to | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,108 @@ | ||
package calculator | ||
|
||
import ( | ||
"context" | ||
"github.com/google/uuid" | ||
chipmunkAPI "github.com/h-varmazyar/Gate/services/chipmunk/api/proto" | ||
indicatorsAPI "github.com/h-varmazyar/Gate/services/indicators/api/proto" | ||
"time" | ||
) | ||
|
||
type RSIValue struct { | ||
gain float64 | ||
loss float64 | ||
Value *float64 | ||
TimeFrame time.Time | ||
} | ||
|
||
type RSI struct { | ||
id uuid.UUID | ||
Period int | ||
Source indicatorsAPI.Source | ||
lastValue RSIValue | ||
lastCandle *chipmunkAPI.Candle | ||
} | ||
|
||
func NewRSI(period int, source indicatorsAPI.Source) (*RSI, error) { | ||
return &RSI{ | ||
id: uuid.New(), | ||
Period: period, | ||
Source: source, | ||
}, nil | ||
} | ||
|
||
func (conf *RSI) Calculate(_ context.Context, candles []*chipmunkAPI.Candle, values []*RSIValue) error { | ||
{ //first RSI | ||
gain := float64(0) | ||
loss := float64(0) | ||
for i := 1; i <= conf.Period; i++ { | ||
if change := candles[i].Close - candles[i-1].Close; change > 0 { | ||
gain += change | ||
} else { | ||
loss += change | ||
} | ||
} | ||
loss *= -1 | ||
gain = gain / float64(conf.Period) | ||
loss = loss / float64(conf.Period) | ||
rs := gain / loss | ||
rsiValue := 100 - (100 / (1 + rs)) | ||
values[conf.Period] = &RSIValue{ | ||
gain: gain, | ||
loss: loss, | ||
Value: &rsiValue, | ||
TimeFrame: time.Unix(candles[conf.Period].Time, 0), | ||
} | ||
conf.lastValue = RSIValue{ | ||
gain: gain, | ||
loss: loss, | ||
Value: &rsiValue, | ||
TimeFrame: time.Unix(candles[conf.Period].Time, 0), | ||
} | ||
} | ||
|
||
for i := 0; i < conf.Period; i++ { | ||
values[i] = &RSIValue{ | ||
gain: 0, | ||
loss: 0, | ||
Value: nil, | ||
TimeFrame: time.Unix(candles[i].Time, 0), | ||
} | ||
} | ||
|
||
for i := conf.Period + 1; i < len(candles); i++ { | ||
conf.lastCandle = cloneCandle(candles[i-1]) | ||
values[i] = conf.calculateRSIValue(candles[i]) | ||
|
||
lastValue := values[i] | ||
conf.lastValue = *lastValue | ||
} | ||
return nil | ||
} | ||
|
||
func (conf *RSI) UpdateLast(_ context.Context, candle *chipmunkAPI.Candle, value *RSIValue) { | ||
value = conf.calculateRSIValue(candle) | ||
lastValue := value | ||
|
||
conf.lastCandle = cloneCandle(candle) | ||
conf.lastValue = *lastValue | ||
} | ||
|
||
func (conf *RSI) calculateRSIValue(candle *chipmunkAPI.Candle) *RSIValue { | ||
gain, loss := float64(0), float64(0) | ||
if change := candle.Close - conf.lastCandle.Close; change > 0 { | ||
gain = change | ||
} else { | ||
loss = change | ||
} | ||
avgGain := (conf.lastValue.gain*float64(conf.Period-1) + gain) / float64(conf.Period) | ||
avgLoss := (conf.lastValue.loss*float64(conf.Period-1) - loss) / float64(conf.Period) | ||
rs := avgGain / avgLoss | ||
rsiValue := 100 - (100 / (1 + rs)) | ||
|
||
return &RSIValue{ | ||
gain: avgGain, | ||
loss: avgLoss, | ||
Value: &rsiValue, | ||
} | ||
} |
Oops, something went wrong.