dev 4
This commit is contained in:
@@ -1,114 +1,38 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"big-qmt/go-client/config"
|
||||
"big-qmt/go-client/libs"
|
||||
"big-qmt/go-client/sdk"
|
||||
)
|
||||
|
||||
type dipWatch struct {
|
||||
LastClose float64
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
var openDip = struct {
|
||||
mu sync.Mutex
|
||||
store map[string]dipWatch
|
||||
}{store: map[string]dipWatch{}}
|
||||
|
||||
func openSignal(ctx context.Context, client *sdk.Client, books *OrderBook, ticks map[string]sdk.Tick, openSignals map[string]libs.SignalItem, marketOK bool, buyBudget *float64) {
|
||||
if !marketOK {
|
||||
return
|
||||
}
|
||||
if buyBudget == nil || *buyBudget <= 0 {
|
||||
return
|
||||
}
|
||||
func openSignal(client *sdk.Client, books *OrderBook, ticks map[string]sdk.Tick, openSignals []libs.SignalItem) {
|
||||
state := getState()
|
||||
if state.LoadError != "" {
|
||||
logf("ERROR", "[ZT][开仓] 状态文件异常,禁止新开仓: %s", state.LoadError)
|
||||
return
|
||||
}
|
||||
for code := range openSignals {
|
||||
if code == "" {
|
||||
logf("ERROR", "[ZT][开仓] 无效股票代码")
|
||||
for _, item := range openSignals {
|
||||
if state.Get(item.Code) != nil {
|
||||
continue
|
||||
}
|
||||
if state.Get(code) != nil {
|
||||
continue
|
||||
}
|
||||
price := ticks[code].LastPrice
|
||||
price := ticks[item.Code].LastPrice
|
||||
if price <= 0 {
|
||||
continue
|
||||
}
|
||||
if !dipTriggered(&openDip.mu, openDip.store, "开仓", code, price) {
|
||||
if !dipTriggered(&openDip.mu, openDip.store, "开仓", item.Code, price) {
|
||||
continue
|
||||
}
|
||||
volume := calcBuyVolume(price, config.Account.BuyValue)
|
||||
volume := libs.CalcBuyVolume(price, config.Account.BuyValue)
|
||||
if volume <= 0 {
|
||||
continue
|
||||
}
|
||||
estimated := price * float64(volume)
|
||||
if estimated > *buyBudget {
|
||||
logf("INFO", "[ZT][开仓] %s 可用买入预算不足,需要=%.2f 剩余=%.2f", code, estimated, *buyBudget)
|
||||
continue
|
||||
}
|
||||
orderID := newOrderTag("base")
|
||||
if !books.place(ctx, client, sideBuy, code, volume, orderID) {
|
||||
if !books.place(ctx, client, sideBuy, item.Code, volume, orderID) {
|
||||
continue
|
||||
}
|
||||
setPending(state.Ensure(code), pendingBaseOpening, orderID)
|
||||
*buyBudget -= estimated
|
||||
setPending(state.Ensure(item.Code), pendingBaseOpening, orderID)
|
||||
state.Save()
|
||||
logf("INFO", "[ZT][开仓] %s 买入 %d 股", code, volume)
|
||||
logf("INFO", "[ZT][开仓] %s 买入 %d 股", item.Code, volume)
|
||||
}
|
||||
}
|
||||
|
||||
func calcBuyVolume(price, buyValue float64) int {
|
||||
if price <= 0 || buyValue <= 0 {
|
||||
return 0
|
||||
}
|
||||
// 不足一手时仍按最低一手委托。
|
||||
hands := int(math.Floor(buyValue / (price * 100)))
|
||||
if hands == 0 {
|
||||
hands = 1
|
||||
}
|
||||
return hands * 100
|
||||
}
|
||||
|
||||
func dipTriggered(mu *sync.Mutex, store map[string]dipWatch, tag, code string, price float64) bool {
|
||||
if price <= 0 {
|
||||
return false
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
now := time.Now()
|
||||
watch, ok := store[code]
|
||||
if !ok || now.After(watch.ExpiresAt) || now.Equal(watch.ExpiresAt) {
|
||||
store[code] = dipWatch{LastClose: price, ExpiresAt: now.Add(time.Duration(config.Account.WatchTimeoutSec) * time.Second)}
|
||||
logf("INFO", "[%s-观察] %s 现价=%.2f", tag, code, price)
|
||||
return false
|
||||
}
|
||||
if price < watch.LastClose {
|
||||
watch.LastClose = price
|
||||
watch.ExpiresAt = now.Add(time.Duration(config.Account.WatchTimeoutSec) * time.Second)
|
||||
store[code] = watch
|
||||
logf("INFO", "[%s-下跌] %s 刷新低点=%.2f", tag, code, price)
|
||||
return false
|
||||
}
|
||||
rebound := (price - watch.LastClose) / watch.LastClose * 100
|
||||
if rebound <= 0 {
|
||||
return false
|
||||
}
|
||||
if rebound < config.Account.ReboundThreshold {
|
||||
logf("INFO", "[%s-等待] %s 反弹=%.2f%% 阈值=%.2f%%", tag, code, rebound, config.Account.ReboundThreshold)
|
||||
return false
|
||||
}
|
||||
delete(store, code)
|
||||
logf("INFO", "[%s-触发] %s 反弹=%.2f%% 低点=%.2f", tag, code, rebound, watch.LastClose)
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user