Skip to content

Commit

Permalink
feat: add test rate
Browse files Browse the repository at this point in the history
  • Loading branch information
HaoZhengZhao committed Nov 9, 2024
1 parent 16c734d commit c2a0691
Show file tree
Hide file tree
Showing 16 changed files with 392 additions and 39 deletions.
39 changes: 17 additions & 22 deletions controllers/command.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package controllers

import (
"go_binance_futures/utils"
"io"
"os"
"os/exec"
"regexp"

"github.com/beego/beego/v2/core/config"
"github.com/beego/beego/v2/server/web"
Expand Down Expand Up @@ -60,27 +57,25 @@ func (ctrl *CommandController) Start() {

// 关闭后台任务
func (ctrl *CommandController) Stop() {
content, err := os.ReadFile("./conf/app.conf")
if err != nil {
ctrl.Ctx.Resp(utils.ResJson(400, nil, "获取错误"))
return
}

pattern := "future_enable = 1"
replacement := "future_enable = 0"
r, err := regexp.Compile(pattern)
if err != nil {
panic(err)
}
result := r.ReplaceAllString(string(content), replacement)
err = os.WriteFile("./conf/app.conf", []byte(result), 0644)
if err != nil {
ctrl.Ctx.Resp(utils.ResJson(400, nil, "写入文件错误"))
return
}
// content, err := os.ReadFile("./conf/app.conf")
// if err != nil {
// ctrl.Ctx.Resp(utils.ResJson(400, nil, "获取错误"))
// return
// }

// pattern := "future_enable = 1"
// replacement := "future_enable = 0"
// r, err := regexp.Compile(pattern)
// if err != nil {
// panic(err)
// }
// result := r.ReplaceAllString(string(content), replacement)
// err = os.WriteFile("./conf/app.conf", []byte(result), 0644)
// if err != nil {
// ctrl.Ctx.Resp(utils.ResJson(400, nil, "写入文件错误"))
// return
// }
commend_stop, _ := config.String("web::commend_stop")

cmd := exec.Command("bash", "-c", commend_stop)
cmd.Start() // 异步执行,不要获取结果,因为重启时此进程会挂掉导致http请求失败

Expand Down
182 changes: 170 additions & 12 deletions controllers/eatRate.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package controllers

import (
fu "go_binance_futures/feature/api/binance"
"go_binance_futures/models"
spot "go_binance_futures/spot/api/binance"
"go_binance_futures/utils"
"strconv"
"sync"
"time"

"github.com/adshao/go-binance/v2/futures"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
"github.com/beego/beego/v2/server/web"
)

Expand All @@ -18,13 +23,16 @@ func (ctrl *EatRateController) Post() {
symbols := new(models.EatRateSymbols)
ctrl.BindJSON(&symbols)

var futureSymbols models.Symbols
orm.NewOrm().QueryTable("symbols").Filter("symbol", symbols.FuturesSymbol).One(&futureSymbols)

symbols.Enable = 0 // 默认不开启
symbols.Type = 1 // 正向套利
symbols.Leverage = 3 // 杠杆类型
symbols.MarginType = "CROSSED" // 杠杆类型 ISOLATED(逐仓), CROSSED(全仓)
symbols.StepSize = "0.1"
symbols.TickSize = "0.1"
symbols.Profit = "0"
symbols.StepSize = futureSymbols.StepSize // 数量精度
symbols.TickSize = futureSymbols.TickSize // 价格精度
symbols.Profit = 0.0

o := orm.NewOrm()
id, err := o.Insert(symbols)
Expand All @@ -44,13 +52,13 @@ func (ctrl *EatRateController) Post() {
}

func (ctrl *EatRateController) Get() {
paramsType := ctrl.GetString("type", "")
paramsSymbol := ctrl.GetString("symbol", "")

o := orm.NewOrm()
var symbols []models.EatRateSymbols
query := o.QueryTable("eat_rate_symbols")
if paramsType != "" {
query = query.Filter("Type", paramsType)
if paramsSymbol != "" {
query = query.Filter("Symbol", paramsSymbol)
}
_, err := query.OrderBy("ID").All(&symbols)
if err != nil {
Expand Down Expand Up @@ -106,25 +114,175 @@ func (ctrl *EatRateController) Delete() {

// 开启吃资金费率
func (ctrl *EatRateController) Start() {
id := ctrl.Ctx.Input.Param(":id")
var symbols models.EatRateSymbols
o := orm.NewOrm()
_, err := o.Raw("UPDATE eat_rate_symbols SET enable = ?, start_time = ?", 1, time.Now().Unix() * 1000).Exec()
o.QueryTable("eat_rate_symbols").Filter("Id", id).One(&symbols)

totalAmountFloat, _ := strconv.ParseFloat(symbols.TotalAmount, 64)

futuresAmount := totalAmountFloat / float64(symbols.Leverage) // 合约
spotAmount := totalAmountFloat - futuresAmount // 现货
spotPriceFloat, err := getSpotPrice(symbols.SpotSymbol) // 现货价格
if err != nil {
logs.Info("not found spot symbol:", symbols.SpotSymbol)
ctrl.Ctx.Resp(utils.ResJson(400, nil, "not found spot"))
}
spotQuantity := spotAmount / spotPriceFloat // 购买数量
spotQuantity = utils.GetTradePrecision(spotQuantity, symbols.StepSize) // 合理精度的数量

futuresPriceFloat, err := getFuturesPrice(symbols.FuturesSymbol) // 合约价格
if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "eat failed"))
logs.Info("not found futures symbol:", symbols.FuturesSymbol)
ctrl.Ctx.Resp(utils.ResJson(400, nil, "not found futures"))
}
futuresQuantity := futuresAmount / futuresPriceFloat * float64(symbols.Leverage) // 做空数量
futuresQuantity = utils.GetTradePrecision(futuresQuantity, symbols.StepSize) // 合理数量精度的价格

var spotOrderId int64
var futuresOrderId int64
var wg sync.WaitGroup
wg.Add(1)
wg.Add(1)
go func() {
defer wg.Done()
// 买入现货
res, err := spot.BuyMarket(symbols.SpotSymbol, spotQuantity)
if err != nil {
logs.Error("spot buy fail, symbol:", symbols.SpotSymbol)
logs.Error("err:", err.Error())
return
}
spotOrderId = res.OrderID
}()
go func() {
defer wg.Done()
// 做空合约
res, err := fu.SellMarket(symbols.FuturesSymbol, futuresQuantity, futures.PositionSideTypeShort)
if err != nil {
logs.Error("futures sell short fail, symbol:", symbols.FuturesSymbol)
logs.Error("err:", err.Error())
return
}
futuresOrderId = res.OrderID
}()
wg.Wait()

if spotOrderId == 0 || futuresOrderId == 0 {
ctrl.Ctx.Resp(utils.ResJson(400, nil, "buy fail"))
return
}

spotOrder, _ := spot.GetOrder(spot.OrderParams{
Symbol: symbols.SpotSymbol,
OrderID: spotOrderId,
})

futuresOrder, _ := fu.GetOrder(fu.OrderParams{
Symbol: symbols.FuturesSymbol,
OrderID: futuresOrderId,
})

// 更新数据表
symbols.Enable = 1
symbols.SpotAmount = strconv.FormatFloat(spotAmount, 'f', -1, 64)
symbols.SpotQuantity = spotQuantity
// symbols.SpotPrice = strconv.FormatFloat(spotPriceFloat, 'f', -1, 64)
symbols.SpotPrice = spotOrder.Price
symbols.SpotOrderId = spotOrderId

symbols.FuturesAmount = strconv.FormatFloat(futuresAmount, 'f', -1, 64)
symbols.FuturesQuantity = futuresQuantity
// symbols.FuturesPrice = strconv.FormatFloat(futuresPriceFloat, 'f', -1, 64)
symbols.FuturesPrice = futuresOrder.Price
symbols.FuturesOrderId = futuresOrderId

nowTime := time.Now().Unix() * 1000
symbols.StartTime = nowTime
symbols.LastProfitTime = nowTime

_, err = o.Update(&symbols)
if err != nil {
logs.Error("update fail, symbol:", symbols.Symbol)
logs.Error("err:", err.Error())
ctrl.Ctx.Resp(utils.ResJson(200, nil))
return
}
ctrl.Ctx.Resp(utils.ResJson(200, nil))
}

// 平仓关闭
func (ctrl *EatRateController) End() {
id := ctrl.Ctx.Input.Param(":id")
var symbols models.EatRateSymbols
o := orm.NewOrm()
_, err := o.Raw("UPDATE eat_rate_symbols SET enable = ?, end_time = ?", 0, time.Now().Unix() * 1000).Exec()
o.QueryTable("eat_rate_symbols").Filter("Id", id).One(&symbols)

var spotOrderId int64
var futuresOrderId int64
var wg sync.WaitGroup
wg.Add(1)
wg.Add(1)
go func() {
defer wg.Done()
// 卖出现货
res, err := spot.SellMarket(symbols.SpotSymbol, symbols.SpotQuantity)
if err != nil {
logs.Error("spot buy fail, symbol:", symbols.SpotSymbol)
logs.Error("err:", err.Error())
return
}
spotOrderId = res.OrderID
}()
go func() {
defer wg.Done()
// 合约平仓
res, err := fu.BuyMarket(symbols.FuturesSymbol, symbols.FuturesQuantity, futures.PositionSideTypeShort)
if err != nil {
logs.Error("futures sell short fail, symbol:", symbols.FuturesSymbol)
logs.Error("err:", err.Error())
return
}
futuresOrderId = res.OrderID
}()
wg.Wait()

if spotOrderId == 0 || futuresOrderId == 0 {
ctrl.Ctx.Resp(utils.ResJson(400, nil, "sell fail"))
return
}

// 更新数据表
symbols.Enable = 0
symbols.EndTime = time.Now().Unix() * 1000
_, err := o.Update(&symbols)
if err != nil {
// 处理错误
ctrl.Ctx.Resp(utils.ResJson(400, nil, "close failed"))
logs.Error("update fail, symbol:", symbols.Symbol)
logs.Error("err:", err.Error())
ctrl.Ctx.Resp(utils.ResJson(200, nil))
return
}

ctrl.Ctx.Resp(utils.ResJson(200, nil))
}

// 现货价格
func getSpotPrice(symbol string) (float64, error) {
spotPrice, err := spot.GetTickerPrice(symbol)
if err != nil {
return 0.0, err
}
spotPriceFloat, _ := strconv.ParseFloat(spotPrice[0].Price, 64)
return spotPriceFloat, err
}

// 合约价格
func getFuturesPrice(symbol string) (float64, error) {
futuresPrice, err := fu.GetTickerPrice(symbol)
if err != nil {
return 0.0, err
}
futuresPriceFloat, _ := strconv.ParseFloat(futuresPrice[0].Price, 64)
return futuresPriceFloat, err
}

Binary file modified db/coin.db
Binary file not shown.
24 changes: 24 additions & 0 deletions doc/income.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// incomeType 收益类型: TRANSFER 转账, WELCOME_BONUS 欢迎奖金, REALIZED_PNL 已实现盈亏, FUNDING_FEE 资金费用, COMMISSION 佣金, INSURANCE_CLEAR 强平, REFERRAL_KICKBACK 推荐人返佣, COMMISSION_REBATE 被推荐人返佣, API_REBATE API佣金回扣, CONTEST_REWARD 交易大赛奖金, CROSS_COLLATERAL_TRANSFER cc转账, OPTIONS_PREMIUM_FEE 期权购置手续费, OPTIONS_SETTLE_PROFIT 期权行权收益, INTERNAL_TRANSFER 内部账户,给普通用户划转, AUTO_EXCHANGE 自动兑换, DELIVERED_SETTELMENT 下架结算, COIN_SWAP_DEPOSIT 闪兑转入, COIN_SWAP_WITHDRAW 闪兑转出, POSITION_LIMIT_INCREASE_FEE 仓位限制上调费用

const data = [
{
"symbol": "", // 交易对,仅针对涉及交易对的资金流
"incomeType": "TRANSFER", // 资金流类型
"income": "-0.37500000", // 资金流数量,正数代表流入,负数代表流出
"asset": "USDT", // 资产内容
"info":"TRANSFER", // 备注信息,取决于流水类型
"time": 1570608000000, // 时间
"tranId":"9689322392", // 划转ID
"tradeId":"" // 引起流水产生的原始交易ID
},
{
"symbol": "BTCUSDT",
"incomeType": "COMMISSION",
"income": "-0.01000000",
"asset": "USDT",
"info":"COMMISSION",
"time": 1570636800000,
"tranId":9689322392,
"tradeId":"2059192"
}
]
58 changes: 57 additions & 1 deletion feature/api/binance/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ func init() {
}
}

type ListOrderParams struct {
type OrderParams struct {
Symbol string
OrderID int64
}

type ListOrderParams struct {
OrderParams
StartTime int64
EndTime int64
Limit int
Expand All @@ -59,6 +63,41 @@ func GetPosition() (res []*futures.PositionRisk, err error){
return res, err
}

type IncomeParams struct {
Symbol string
IncomeType string
StartTime int64
EndTime int64
Limit int64
}

// @returns /doc/income.js
func GetIncome(incomeParams IncomeParams) (res []*futures.IncomeHistory, err error){
query := futuresClient.NewGetIncomeHistoryService()
if (incomeParams.Symbol != "") {
query = query.Symbol(incomeParams.Symbol)
}
if (incomeParams.IncomeType != "") {
query = query.IncomeType(incomeParams.IncomeType)
}
if (incomeParams.StartTime != 0) {
query = query.StartTime(incomeParams.StartTime)
}
if (incomeParams.EndTime != 0) {
query = query.EndTime(incomeParams.EndTime)
}
if (incomeParams.Limit != 0) {
query = query.Limit(incomeParams.Limit)
}
res, err = query.Do(context.Background())
if err != nil {
logs.Error(err)
return nil, err
}
// logs.Info(utils.ToJson(res))
return res, err
}

func GetDepth(symbol string, limits ...int) (res *futures.DepthResponse, err error) {
limit := 100 // 默认值
if len(limits) != 0 {
Expand Down Expand Up @@ -281,6 +320,23 @@ func GetOrders(listOrderParams ListOrderParams) (res []*futures.Order, err error
return res, err
}

// 获取某个订单
func GetOrder(orderParams OrderParams) (res *futures.Order, err error) {
service := futuresClient.NewGetOrderService()
if orderParams.Symbol != "" {
service = service.Symbol(orderParams.Symbol)
}
if orderParams.OrderID != 0 {
service = service.OrderID(orderParams.OrderID)
}
res, err = service.Do(context.Background())
if err != nil {
logs.Error(err)
return nil, err
}
return res, err
}

// @param startTime ex:(time.Now().Unix() - 60 * 60 * 24) // 获取最近1天的交易订单
// @see https://binance-docs.github.io/apidocs/futures/cn/#user_data-7
func GetLimitStartTimeOrders(startTime int64) (res []*futures.Order, err error) {
Expand Down
Loading

0 comments on commit c2a0691

Please sign in to comment.