26 changed files with 465 additions and 173 deletions
@ -1,25 +0,0 @@
|
||||
syntax = "proto3"; |
||||
|
||||
import "api/pub.proto"; |
||||
|
||||
option go_package = "./pb"; |
||||
|
||||
service IndicatorService { |
||||
rpc Subscribe(IndicatorSubReq) returns (stream Indicator); // 订阅指标 |
||||
rpc Plot(Indicator) returns (Indicator); // 绘图 |
||||
} |
||||
|
||||
message IndicatorSubReq { |
||||
string topic = 1; |
||||
string instId = 2; |
||||
int32 window = 3; |
||||
} |
||||
|
||||
message Indicator { |
||||
ExchangeType exhcange = 1; |
||||
string instId = 2; |
||||
string indicator = 3; |
||||
string sub = 4; // 指标子标题, MA5, MA10, MA20 |
||||
int64 Ts = 5; |
||||
bytes payload = 8; |
||||
} |
||||
@ -0,0 +1,38 @@
|
||||
syntax = "proto3"; |
||||
|
||||
import "api/pub.proto"; |
||||
|
||||
option go_package = "./pb"; |
||||
|
||||
service OrderService { |
||||
// request-response |
||||
rpc SubmitOrder(OrderSubmitReq) returns (OrderSubmitRsp) {} |
||||
// rpc CancelOrder(CancelOrderRequest) returns (CancelOrderResponse) {} |
||||
// rpc QueryOrder(QueryOrderRequest) returns (QueryOrderResponse) {} |
||||
// rpc QueryOrders(QueryOrdersRequest) returns (QueryOrdersResponse) {} |
||||
// rpc QueryTrades(QueryTradesRequest) returns (QueryTradesResponse) {} |
||||
} |
||||
|
||||
message OrderSubmit { |
||||
string session = 1; |
||||
string exchange = 2; |
||||
string symbol = 3; |
||||
Side side = 4; |
||||
string price = 6; |
||||
string quantity = 5; |
||||
string stop_price = 7; |
||||
OrderType order_type = 8; |
||||
string client_order_id = 9; |
||||
int64 group_id = 10; |
||||
} |
||||
|
||||
message OrderSubmitReq { |
||||
string session = 1; |
||||
repeated OrderSubmit submit_orders = 2; |
||||
} |
||||
|
||||
message OrderSubmitRsp { |
||||
string session = 1; |
||||
repeated Order orders = 2; |
||||
Error error = 3; |
||||
} |
||||
@ -1,35 +0,0 @@
|
||||
package indicator |
||||
|
||||
import ( |
||||
"fmt" |
||||
"sig-pub/api/pb" |
||||
"sig-pub/pkg/types" |
||||
) |
||||
|
||||
type RSI struct { |
||||
// types.IntervalWindow
|
||||
window int // 窗口大小
|
||||
} |
||||
|
||||
func (ind *RSI) IntervalWindow() { |
||||
// 指标参数注入
|
||||
} |
||||
|
||||
func (ind *RSI) QueryRange(exchange pb.ExchangeType, instId string, interval types.Interval, rsi int) (query string, err error) { |
||||
var r types.MeticMatrix |
||||
_ = r |
||||
intervalAdder, ok := types.SupportedIntervals[interval] |
||||
if !ok { |
||||
err = fmt.Errorf("unsupport interval %s", interval) |
||||
return |
||||
} |
||||
minutes := intervalAdder(0, int64(rsi)) / 1000 / 60 |
||||
|
||||
query = fmt.Sprintf(` |
||||
100 - 100 / (1 + ( |
||||
avg_over_time(clamp_min(delta(%s{kind="close", interval="%s", exchange="%s"}), 0)[%dm]) / |
||||
avg_over_time(abs(clamp_max(delta(%s{kind="close", interval="%s", exchange="%s"}), 0))[%dm]) |
||||
)) |
||||
`, instId, interval, exchange, minutes, instId, interval, exchange, minutes) |
||||
return |
||||
} |
||||
@ -1,4 +1,4 @@
|
||||
package trading |
||||
package order |
||||
|
||||
// 交易服务
|
||||
// load strategy plugins
|
||||
@ -0,0 +1,56 @@
|
||||
package trading |
||||
|
||||
import ( |
||||
"sig-pub/api/pb" |
||||
"sig-pub/pkg/types" |
||||
"sig-pub/pkg/types/series" |
||||
) |
||||
|
||||
type KlineSeries struct { |
||||
Exchange pb.ExchangeType |
||||
InstId string |
||||
Interval types.Interval |
||||
Ts int64 |
||||
klines []*types.Kline |
||||
klineStore KlineStore |
||||
} |
||||
|
||||
func NewKlineSeries(ts int64, interval types.Interval, klineStore KlineStore) KlineSeries { |
||||
return KlineSeries{ |
||||
Ts: ts, |
||||
Interval: interval, |
||||
klineStore: klineStore, |
||||
} |
||||
} |
||||
|
||||
// Get
|
||||
// [0]当前k线
|
||||
func (a KlineSeries) Get(start int16) (kline types.Kline) { |
||||
ts := a.Interval.MustAddMul(a.Ts, int64(-start)) |
||||
|
||||
for _, k := range a.klines { |
||||
if k.Ts == ts { |
||||
return *k |
||||
} |
||||
} |
||||
// todo query tsdb
|
||||
return |
||||
} |
||||
|
||||
// Series [start...end]
|
||||
func (a KlineSeries) Series(start, end int16) (klines series.Klines) { |
||||
endTs := a.Interval.MustAddMul(a.Ts, int64(-start)) |
||||
startTs := a.Interval.MustAddMul(a.Ts, int64(-end)) |
||||
_ = endTs |
||||
_ = startTs |
||||
// return a.klineStore.GetRange(startTs, endTs)
|
||||
// todo
|
||||
return |
||||
} |
||||
|
||||
func (s *KlineSeries) Update(kline *types.Kline) []types.Kline { |
||||
s.klines = append(s.klines, kline) |
||||
// todo copy(s.klines, s.klines[0:1]) set index=20, ts=kline.ts
|
||||
s.Ts = kline.Ts |
||||
return nil |
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
package trading |
||||
|
||||
import ( |
||||
"sig-pub/api/pb" |
||||
vmts "sig-pub/pkg/storage/tsdb/victoria_metrics" |
||||
"sig-pub/pkg/types" |
||||
"sig-pub/pkg/utils/collect" |
||||
) |
||||
|
||||
type KlineStore struct { |
||||
vmdb vmts.VictoriaMetricsTSDB |
||||
store [3]*collect.ConcurrentMap[string, collect.ConcurrentMap[types.Interval, *KlineSeries]] // K线列表: []exchange<instId, interval, klines>
|
||||
} |
||||
|
||||
func NewKlineSeriesStore(vmdb vmts.VictoriaMetricsTSDB) (kss *KlineStore) { |
||||
kss = &KlineStore{ |
||||
vmdb: vmdb, |
||||
} |
||||
kss.store[pb.ExchangeType_OKX] = collect.NewConcurrentMap[string, collect.ConcurrentMap[types.Interval, *KlineSeries]](64, func(s string) string { return s }) |
||||
// kss.klines[pb.ExchangeType_BINANCE] =
|
||||
return |
||||
} |
||||
|
||||
func (s *KlineStore) Update(exchange pb.ExchangeType, kline *types.Kline) (k types.Kline) { |
||||
|
||||
return |
||||
} |
||||
@ -0,0 +1,23 @@
|
||||
package indicator |
||||
|
||||
import ( |
||||
"sig-pub/pkg/types" |
||||
"sig-pub/pkg/types/series" |
||||
) |
||||
|
||||
// IIndicator 指标基础计算接口
|
||||
type IIndicator interface { |
||||
Calculate() (vector float64) |
||||
} |
||||
|
||||
// IKlineSeries k线序列, strategy服务提供
|
||||
type IKlineSeries interface { |
||||
Get(start int16) (kline types.Kline) |
||||
Series(start, end int16) (klines series.Klines) |
||||
} |
||||
|
||||
// IIndicatorSeries 指标序列, 供策略读取, strategy服务提供
|
||||
type IIndicatorSeries interface { |
||||
Get(start int16) (vector float64) |
||||
Series(start, end int16) (matrix series.Floats) |
||||
} |
||||
@ -0,0 +1,61 @@
|
||||
package indicator |
||||
|
||||
import ( |
||||
"fmt" |
||||
"sig-pub/pkg/trader" |
||||
"sig-pub/pkg/types" |
||||
"sig-pub/pkg/types/series" |
||||
|
||||
"github.com/spf13/cast" |
||||
) |
||||
|
||||
// RSI0: 相对强弱指数 (RSI0)
|
||||
// rsi define: https://www.investopedia.com/terms/r/rsi.asp
|
||||
type RSI0 struct { |
||||
trader.Indicator |
||||
series.Series |
||||
values series.Floats |
||||
prices series.Floats |
||||
|
||||
argBaseDay int32 |
||||
} |
||||
|
||||
func NewRSI() *RSI0 { |
||||
return &RSI0{} |
||||
} |
||||
|
||||
func (ind RSI0) Meta() trader.IndicatorMeta { |
||||
return trader.IndicatorMeta{ |
||||
Name: "RSI", |
||||
Desc: "", |
||||
Args: []trader.Arg{ |
||||
{Name: "基准天数", Desc: "", ArgType: trader.ArgTypeUInt}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func (ind *RSI0) Init(indId int64, exchange any, args []string) (code trader.ErrorCode, err error) { |
||||
arg0, err := cast.ToInt32E(args[0]) |
||||
if err != nil { |
||||
return |
||||
} |
||||
ind.argBaseDay = arg0 |
||||
|
||||
cast.ToIntE("1") |
||||
return |
||||
} |
||||
|
||||
func (ind *RSI0) Update(klines []types.Kline) (err error) { |
||||
for _, kline := range klines { |
||||
c, ok := kline.Close.Float64() |
||||
if !ok { |
||||
err = fmt.Errorf("kline close to float64 error: %s", kline.Close.String()) |
||||
return |
||||
} |
||||
ind.prices.Push(c) |
||||
} |
||||
|
||||
diff := ind.prices.Diff() |
||||
_ = diff |
||||
return |
||||
} |
||||
@ -0,0 +1,15 @@
|
||||
package decimals |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/govalues/decimal" |
||||
) |
||||
|
||||
func MustToFloat64(v decimal.Decimal) float64 { |
||||
f, ok := v.Float64() |
||||
if !ok { |
||||
panic(fmt.Errorf("decimal to float64 error: %v", v)) |
||||
} |
||||
return f |
||||
} |
||||
@ -1,23 +0,0 @@
|
||||
package series |
||||
|
||||
import ( |
||||
"sig-pub/pkg/types" |
||||
|
||||
"github.com/govalues/decimal" |
||||
) |
||||
|
||||
func Klines2Decimals(klines []types.Kline, mapping func(kline types.Kline) decimal.Decimal) (r Decimals) { |
||||
r = NewDecimals(len(klines)) |
||||
for _, k := range klines { |
||||
r.Push(mapping(k)) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func Klines2Floats(klines []types.Kline, mapping func(kline types.Kline) float64) (r Floats) { |
||||
r = NewFloats(len(klines)) |
||||
for _, k := range klines { |
||||
r.Push(mapping(k)) |
||||
} |
||||
return |
||||
} |
||||
@ -0,0 +1,37 @@
|
||||
package series |
||||
|
||||
import ( |
||||
"sig-pub/pkg/types" |
||||
"sig-pub/pkg/types/decimals" |
||||
"sig-pub/pkg/utils/collect" |
||||
) |
||||
|
||||
type Klines []types.Kline |
||||
|
||||
func (s Klines) Times() []int64 { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) int64 { return k.Ts }) |
||||
} |
||||
|
||||
func (s Klines) Open() Floats { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) float64 { return decimals.MustToFloat64(k.Open) }) |
||||
} |
||||
|
||||
func (s Klines) Close() Floats { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) float64 { return decimals.MustToFloat64(k.Close) }) |
||||
} |
||||
|
||||
func (s Klines) High() Floats { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) float64 { return decimals.MustToFloat64(k.High) }) |
||||
} |
||||
|
||||
func (s Klines) Low() Floats { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) float64 { return decimals.MustToFloat64(k.Low) }) |
||||
} |
||||
|
||||
func (s Klines) Vol() Floats { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) float64 { return decimals.MustToFloat64(k.Vol) }) |
||||
} |
||||
|
||||
func (s Klines) VolQuote() Floats { |
||||
return collect.Mapping(s, func(_ int, k types.Kline) float64 { return decimals.MustToFloat64(k.VolQuote) }) |
||||
} |
||||
Loading…
Reference in new issue