Skip to content

Commit

Permalink
feat: add listen coin
Browse files Browse the repository at this point in the history
  • Loading branch information
HaoZhengZhao committed Jul 7, 2024
1 parent cd80a88 commit a01a328
Show file tree
Hide file tree
Showing 22 changed files with 313 additions and 9 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
- 自动买入并自动挂止盈止损单
![合约通知](./img/feature_notice.jpg)


#### 行情监听
TODO

### 使用注意事项
- 网络必须处于大陆之外(因为币安接口大陆正常无法访问)
- 申请api_key地址: [币安API管理页面](https://www.binance.com/cn/usercenter/settings/api-management)
Expand Down Expand Up @@ -171,7 +175,8 @@ bee pack -be GOOS=windows
- [X] 添加独立的币种配置收益率
- [X] 添加一键修改所有币种的配置
- [X] 系统首页显示(那些服务开启和关闭)
- [ ] 添加新的交易策略
- [ ] 添加定时自动交易(吃资金费用)
- [ ] 监听币种在3分钟之内变化幅度大于(2%),报警通知
- [ ] 学习蜡烛图结合其它数据,报警通知
- [ ] 添加新的自动交易策略
- [ ] 添加定时自动交易(现货买入和一倍合约等价格对冲,吃资金费用)
- [ ] 监听币种的价格突变情况,报警通知
- [ ] 学习蜡烛图结合其它数据,报警通知
- [ ] 监控资金流入流出,报警通知
4 changes: 4 additions & 0 deletions conf/app.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ new_enable = 0
# 设定的价格提醒币种
enable = 0

[listen_coin]
# 监听的币种
enable = 0

[web]
# 监听端口
port = 3333
Expand Down
4 changes: 4 additions & 0 deletions controllers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func (ctrl *IndexController) GetServiceConfig() {

var noticeCoinEnable, _ = config.String("notice_coin::enable")

var listenCoinEnable, _ = config.String("listen_coin::enable")

ctrl.Ctx.Resp(map[string]interface{} {
"code": 200,
"data": map[string]interface{} {
Expand All @@ -46,6 +48,8 @@ func (ctrl *IndexController) GetServiceConfig() {
"spotNewEnable": spotNewEnable,

"noticeCoinEnable": noticeCoinEnable,

"listenCoinEnable": listenCoinEnable,
},
"msg": "success",
})
Expand Down
116 changes: 116 additions & 0 deletions controllers/listenCoin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package controllers

import (
"strconv"

"go_binance_futures/models"
"go_binance_futures/utils"

"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/server/web"
)

type ListenCoinController struct {
web.Controller
}

func (ctrl *ListenCoinController) Get() {
paramsType := ctrl.GetString("type", "")

o := orm.NewOrm()
var symbols []models.ListenSymbols
query := o.QueryTable("listen_symbols")
if paramsType != "" {
query = query.Filter("Type", paramsType)
}
_, err := query.OrderBy("ID").All(&symbols)
if err != nil {
ctrl.Ctx.Resp(utils.ResJson(400, nil, err.Error()))
}

ctrl.Ctx.Resp(map[string]interface{} {
"code": 200,
"data": symbols,
"msg": "success",
})
}

func (ctrl *ListenCoinController) Edit() {
id := ctrl.Ctx.Input.Param(":id")
var symbols models.ListenSymbols
o := orm.NewOrm()
o.QueryTable("listen_symbols").Filter("Id", id).One(&symbols)

ctrl.BindJSON(&symbols)

_, err := o.Update(&symbols) // _ 是受影响的条数
if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "修改失败"))
return
}
ctrl.Ctx.Resp(map[string]interface{} {
"code": 200,
"data": symbols,
"msg": "success",
})
}

func (ctrl *ListenCoinController) Delete() {
id := ctrl.Ctx.Input.Param(":id")
symbols := new(models.ListenSymbols)
intId, _ := strconv.ParseInt(id, 10, 64)
symbols.ID = intId
o := orm.NewOrm()

_, err := o.Delete(symbols)
if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "删除错误"))
return
}
ctrl.Ctx.Resp(map[string]interface{} {
"code": 200,
"msg": "success",
})
}

func (ctrl *ListenCoinController) Post() {
symbols := new(models.ListenSymbols)
ctrl.BindJSON(&symbols)

symbols.Enable = 0 // 默认不开启
symbols.KlineInterval = "1m" // 默认k线周期
symbols.ChangePercent = "1.1" // 1.1% 默认变化幅度
symbols.LastNoticeTime = 0 // 最后一次通知时间
symbols.NoticeLimitMin = 5 // 最小通知间隔

o := orm.NewOrm()
id, err := o.Insert(symbols)

if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "新增失败"))
return
}
symbols.ID = id

ctrl.Ctx.Resp(map[string]interface{} {
"code": 200,
"data": symbols,
"msg": "success",
})
}

func (ctrl *ListenCoinController) UpdateEnable() {
flag := ctrl.Ctx.Input.Param(":flag")

o := orm.NewOrm()
_, err := o.Raw("UPDATE listen_symbols SET enable = ?", flag).Exec()
if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "更新错误"))
return
}
ctrl.Ctx.Resp(utils.ResJson(200, nil))
}
2 changes: 1 addition & 1 deletion controllers/noticeCoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (ctrl *NoticeCoinController) UpdateEnable() {
flag := ctrl.Ctx.Input.Param(":flag")

o := orm.NewOrm()
_, err := o.Raw("UPDATE newSymbols SET enable = ?", flag).Exec()
_, err := o.Raw("UPDATE notice_symbols SET enable = ?", flag).Exec()
if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "更新错误"))
Expand Down
Binary file modified db/coin.db
Binary file not shown.
53 changes: 53 additions & 0 deletions feature/feature_listen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package feature

import (
"go_binance_futures/feature/api/binance"
"go_binance_futures/feature/notify"
"go_binance_futures/models"
"strconv"

"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
)

func ListenCoin() {
o := orm.NewOrm()
var coins []models.ListenSymbols
o.QueryTable("listen_symbols").OrderBy("ID").Filter("enable", 1).Filter("type", 2).All(&coins) // 通知币列表

for _, coin := range coins {
logs.Info("监听合约币种:", coin.Symbol)
kline_1, err1 := binance.GetKlineData(coin.Symbol, coin.KlineInterval, 10)
if err1 != nil {
logs.Error("k线错误, 合约币种是:", coin.Symbol)
continue
}

percentLimit, _ := strconv.ParseFloat(coin.ChangePercent, 64)
percentLimit = percentLimit / 100 // 变化幅度

lastOpenPrice, _ := strconv.ParseFloat(kline_1[1].Open, 64) // 上一根 k 线的开盘价
nowPrice, _ := strconv.ParseFloat(kline_1[0].Close, 64) // 当前价格

if (nowPrice > lastOpenPrice) &&
(nowPrice - lastOpenPrice) / lastOpenPrice >= percentLimit &&
((kline_1[0].CloseTime - coin.LastNoticeTime >= 60 * 1000 * coin.NoticeLimitMin && coin.LastNoticeType == "up") || coin.LastNoticeType != "up") {
// 价格上涨
coin.LastNoticeTime = kline_1[0].CloseTime
coin.LastNoticeType = "up"
orm.NewOrm().Update(&coin)

notify.ListenFutureCoin(coin.Symbol, "极速上涨", (nowPrice - lastOpenPrice) / lastOpenPrice)
}
if (nowPrice < lastOpenPrice) &&
(lastOpenPrice - nowPrice) / lastOpenPrice >= percentLimit &&
((kline_1[0].CloseTime - coin.LastNoticeTime >= 60 * 1000 * coin.NoticeLimitMin && coin.LastNoticeType == "down") || coin.LastNoticeType != "down") {
// 价格下跌
coin.LastNoticeTime = kline_1[0].CloseTime
coin.LastNoticeType = "down"
orm.NewOrm().Update(&coin)

notify.ListenFutureCoin(coin.Symbol, "极速下跌", (lastOpenPrice - nowPrice) / lastOpenPrice)
}
}
}
12 changes: 12 additions & 0 deletions feature/notify/dingding.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,16 @@ func NoticeFutureCoin(symbol string, side string, price string, autoOrder string
> author <[email protected]>`
DingDing(fmt.Sprintf(text, symbol, symbol, side, price, autoOrder, time.Now().Format("2006-01-02 15:04:05")))
}

func ListenFutureCoin(symbol string, listenType string, percent float64) {
text := `
## %s合约k线监控通知
#### **币种**:%s
#### **类型**:<font color="#008000">%s</font>
#### **当前变化率**:<font color="#008000">%f</font>
#### **时间**:%s
> author <[email protected]>`
DingDing(fmt.Sprintf(text, symbol, symbol, listenType, percent, time.Now().Format("2006-01-02 15:04:05")))
}
15 changes: 15 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var tradeEnable, _ = config.String("trade::future_enable")
var tradeNewEnable, _ = config.String("trade::new_enable")
var spotNewEnable, _ = config.String("spot::new_enable")
var noticeCoinEnable, _ = config.String("notice_coin::enable")
var listenCoinEnable, _ = config.String("listen_coin::enable")
var taskSleepTimeInt, _ = strconv.Atoi(taskSleepTime)

func init() {
Expand All @@ -42,6 +43,7 @@ func registerModels() {
orm.RegisterModel(new(models.Symbols))
orm.RegisterModel(new(models.NewSymbols))
orm.RegisterModel(new(models.NoticeSymbols))
orm.RegisterModel(new(models.ListenSymbols))

orm.RegisterDriver("sqlite3", orm.DRSqlite)
orm.RegisterDataBase("default", "sqlite3", "./db/coin.db")
Expand Down Expand Up @@ -130,6 +132,19 @@ func main() {
}()
}

if listenCoinEnable == "1" {
logs.Info("行情监听通知开启")
go func() {
for {
spot.ListenCoin()
feature.ListenCoin()

// 等待 taskSleepTimeInt 秒再继续执行
time.Sleep(time.Millisecond * 500)
}
}()
}

// web
web.Run(":" + webPort)
}
Expand Down
18 changes: 18 additions & 0 deletions models/tableStruct.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ type NoticeSymbols struct {
UpdateTime int64 `orm:"column(updateTime)" json:"updateTime"`
}

type ListenSymbols struct {
ID int64 `orm:"column(id)" json:"id"`
Symbol string `orm:"column(symbol)" json:"symbol"`
Enable int `orm:"column(enable)" json:"enable"` // 是否开启
Type int64 `orm:"column(type)" json:"type"` // 1:币币交易 2:合约交易
KlineInterval string `orm:"column(kline_interval)" json:"kline_interval"` // 选定的k线周期
ChangePercent string `orm:"column(change_percent)" json:"change_percent"` // 通知的变化百分比阈值
LastNoticeTime int64 `orm:"column(last_notice_time)" json:"last_notice_time"` // 上一次通知的时间
LastNoticeType string `orm:"column(last_notice_type)" json:"last_notice_type"` // 上一次通知的类型(up/down)
NoticeLimitMin int64 `orm:"column(notice_limit_min)" json:"notice_limit_min"` // 通知频率限制(分钟)
CreateTime int64 `orm:"column(createTime)" json:"createTime"`
UpdateTime int64 `orm:"column(updateTime)" json:"updateTime"`
}

func (u *Order) TableName() string {
return "order"
}
Expand All @@ -94,3 +108,7 @@ func (u *NewSymbols) TableName() string {
func (u *NoticeSymbols) TableName() string {
return "notice_symbols"
}

func (u *ListenSymbols) TableName() string {
return "listen_symbols"
}
4 changes: 4 additions & 0 deletions routers/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ func init() {
web.Router("/notice/coin/:id", &controllers.NoticeCoinController{}, "delete:Delete;put:Edit") // 更新和删除
web.Router("/notice/coin/enable/:flag", &controllers.NoticeCoinController{}, "put:UpdateEnable") // 修改所有的交易对开启关闭

web.Router("/listen/coin", &controllers.ListenCoinController{}, "get:Get;post:Post") // 列表查询和新增
web.Router("/listen/coin/:id", &controllers.ListenCoinController{}, "delete:Delete;put:Edit") // 更新和删除
web.Router("/listen/coin/enable/:flag", &controllers.ListenCoinController{}, "put:UpdateEnable") // 修改所有的交易对开启关闭

web.Router("/orders", &controllers.OrderController{}, "get:Get;delete:DeleteAll") // order list 和 删除所有 order
web.Router("/config", &controllers.ConfigController{}, "get:Get;put:Edit") // config get and edit

Expand Down
18 changes: 18 additions & 0 deletions spot/api/binance/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package binance
import (
"context"
"go_binance_futures/utils"
"sort"
"strconv"

"github.com/adshao/go-binance/v2"
Expand Down Expand Up @@ -37,6 +38,23 @@ func GetExchangeInfo(symbols ...string)(res *binance.ExchangeInfo, err error) {
return res, err
}

// @param symbol 交易对名称,例如:BTCUSDT
// @param interval K线的时间间隔,例如:1m, 3m, 5m, 15m, 30m, 1h等
// @param limit 返回的K线数据条数
// @returns /doc/kine.js
func GetKlineData(symbol string, interval string, limit int) (klines []*binance.Kline, err error) {
klines, err = client.NewKlinesService().Symbol(symbol).Interval(interval).Limit(limit).Do(context.Background())
if err != nil {
logs.Error(err)
return nil, err
}
sort.Slice(klines, func(i, j int) bool {
return klines[i].OpenTime > klines[j].OpenTime // 按照时间降序()
})
// logs.Info(utils.ToJson(klines))
return klines, err
}

// 获取交易价格
func GetTickerPrice(symbol string) (res []*binance.SymbolPrice, err error) {
res, err = client.NewListPricesService().Symbol(symbol).Do(context.Background())
Expand Down
11 changes: 11 additions & 0 deletions spot/notify/dingding.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,14 @@ func NoticeSpotCoin(symbol string, side string, price string, autoOrder string)
DingDing(fmt.Sprintf(text, symbol, symbol, side, price, autoOrder, time.Now().Format("2006-01-02 15:04:05")))
}

func ListenSpotCoin(symbol string, listenType string, percent float64) {
text := `
## %s现货k线监控通知
#### **币种**:%s
#### **类型**:<font color="#008000">%s</font>
#### **当前变化率**:<font color="#008000">%f</font>
#### **时间**:%s
> author <[email protected]>`
DingDing(fmt.Sprintf(text, symbol, symbol, listenType, percent, time.Now().Format("2006-01-02 15:04:05")))
}
Loading

0 comments on commit a01a328

Please sign in to comment.