feat: 添加新股通知
This commit is contained in:
267
handler/newbond/service.go
Normal file
267
handler/newbond/service.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package newbond
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.lxtend.com/qqbot/action"
|
||||
"git.lxtend.com/qqbot/model"
|
||||
"git.lxtend.com/qqbot/sqlite3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
createNewBondListenGroupTableSQL := `
|
||||
CREATE TABLE IF NOT EXISTS new_bond_listen_group (
|
||||
group_id INT PRIMARY KEY
|
||||
);
|
||||
`
|
||||
createNewBondInfoTableSQL := `CREATE TABLE BondData (
|
||||
SecurityCode VARCHAR(10) NOT NULL,
|
||||
SecuCode VARCHAR(15) NOT NULL,
|
||||
TradeMarket VARCHAR(10) NOT NULL,
|
||||
SecurityNameAbbr VARCHAR(50) NOT NULL,
|
||||
DelistDate DATETIME NULL,
|
||||
ListingDate DATETIME NULL,
|
||||
ConvertStockCode VARCHAR(10) NOT NULL,
|
||||
BondExpire VARCHAR(5) NOT NULL,
|
||||
Rating VARCHAR(5) NOT NULL,
|
||||
ValueDate DATETIME NOT NULL,
|
||||
IssueYear VARCHAR(4) NOT NULL,
|
||||
CeaseDate DATETIME NOT NULL,
|
||||
ExpireDate DATETIME NOT NULL,
|
||||
PayInterestDay VARCHAR(10) NOT NULL,
|
||||
InterestRateExplain TEXT NOT NULL,
|
||||
BondCombineCode VARCHAR(20) NOT NULL,
|
||||
ActualIssueScale DECIMAL(10, 2) NOT NULL,
|
||||
IssuePrice DECIMAL(10, 2) NOT NULL,
|
||||
Remark TEXT NOT NULL,
|
||||
ParValue DECIMAL(10, 2) NOT NULL,
|
||||
IssueObject TEXT NOT NULL,
|
||||
RedeemType VARCHAR(50) NULL,
|
||||
ExecuteReasonHS VARCHAR(255) NULL,
|
||||
NoticeDateHS DATETIME NULL,
|
||||
NoticeDateSH DATETIME NULL,
|
||||
ExecutePriceHS DECIMAL(10, 2) NULL,
|
||||
ExecutePriceSH DECIMAL(10, 2) NULL,
|
||||
RecordDateSH DATETIME NULL,
|
||||
ExecuteStartDateSH DATETIME NULL,
|
||||
ExecuteStartDateHS DATETIME NULL,
|
||||
ExecuteEndDate DATETIME NULL,
|
||||
CorreCode VARCHAR(10) NOT NULL,
|
||||
CorreCodeNameAbbr VARCHAR(50) NOT NULL,
|
||||
PublicStartDate DATETIME NOT NULL,
|
||||
CorreCodeO VARCHAR(10) NOT NULL,
|
||||
CorreCodeNameAbbrO VARCHAR(50) NOT NULL,
|
||||
BondStartDate DATETIME NOT NULL,
|
||||
SecurityStartDate DATETIME NOT NULL,
|
||||
SecurityShortName VARCHAR(50) NOT NULL,
|
||||
FirstPerPreplacing DECIMAL(10, 4) NOT NULL,
|
||||
OnlineGeneralAAU DECIMAL(10, 2) NOT NULL,
|
||||
OnlineGeneralLWR DECIMAL(20, 10) NOT NULL,
|
||||
InitialTransferPrice DECIMAL(10, 2) NOT NULL,
|
||||
TransferEndDate DATETIME NOT NULL,
|
||||
TransferStartDate DATETIME NOT NULL,
|
||||
ResaleClause TEXT NOT NULL,
|
||||
RedeemClause TEXT NOT NULL,
|
||||
PartyName VARCHAR(100) NOT NULL,
|
||||
ConvertStockPrice DECIMAL(10, 2) NOT NULL,
|
||||
TransferPrice DECIMAL(10, 2) NOT NULL,
|
||||
TransferValue DECIMAL(10, 4) NOT NULL,
|
||||
CurrentBondPrice VARCHAR(10) NOT NULL,
|
||||
TransferPremiumRatio DECIMAL(10, 2) NOT NULL,
|
||||
ConvertStockPriceHQ DECIMAL(10, 2) NULL,
|
||||
Market VARCHAR(50) NULL,
|
||||
ResaleTrigPrice DECIMAL(10, 2) NOT NULL,
|
||||
RedeemTrigPrice DECIMAL(10, 2) NOT NULL,
|
||||
PBVRatio DECIMAL(10, 2) NOT NULL,
|
||||
IBStartDate DATETIME NOT NULL,
|
||||
IBEndDate DATETIME NOT NULL,
|
||||
CashflowDate DATETIME NOT NULL,
|
||||
CouponIR DECIMAL(10, 2) NOT NULL,
|
||||
ParamName TEXT NOT NULL,
|
||||
IssueType VARCHAR(10) NOT NULL,
|
||||
ExecuteReasonSH VARCHAR(255) NULL,
|
||||
PaydayNew VARCHAR(10) NOT NULL,
|
||||
CurrentBondPriceNew DECIMAL(10, 2) NOT NULL,
|
||||
IsConvertStock VARCHAR(10) NOT NULL,
|
||||
IsRedeem VARCHAR(10) NOT NULL,
|
||||
IsSellback VARCHAR(10) NOT NULL,
|
||||
FirstProfit DECIMAL(10, 2) NULL,
|
||||
PRIMARY KEY (SecurityCode)
|
||||
);
|
||||
`
|
||||
sqlite3.TryCreateTable(createNewBondListenGroupTableSQL)
|
||||
sqlite3.TryCreateTable(createNewBondInfoTableSQL)
|
||||
go RoundCheckNewBond()
|
||||
}
|
||||
|
||||
func GetBondsData() ([]BondData, error) {
|
||||
url := "https://datacenter-web.eastmoney.com/api/data/v1/get?sortColumns=PUBLIC_START_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber=1&reportName=RPT_BOND_CB_LIST&columns=ALL"eColumns=f2~01~CONVERT_STOCK_CODE~CONVERT_STOCK_PRICE%2Cf235~10~SECURITY_CODE~TRANSFER_PRICE%2Cf236~10~SECURITY_CODE~TRANSFER_VALUE%2Cf2~10~SECURITY_CODE~CURRENT_BOND_PRICE%2Cf237~10~SECURITY_CODE~TRANSFER_PREMIUM_RATIO%2Cf239~10~SECURITY_CODE~RESALE_TRIG_PRICE%2Cf240~10~SECURITY_CODE~REDEEM_TRIG_PRICE%2Cf23~01~CONVERT_STOCK_CODE~PBV_RATIO"eType=0&source=WEB&client=WEB"
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var apiResponse BondResponse
|
||||
err = json.Unmarshal(body, &apiResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiResponse.Result.Data, nil
|
||||
}
|
||||
|
||||
func AddGroupListen(groupID int) error {
|
||||
tx, err := sqlite3.GetTran()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
tx.Exec("INSERT INTO new_bond_listen_group (group_id) VALUES (?)", groupID)
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveGroupListen(groupID int) error {
|
||||
tx, err := sqlite3.GetTran()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
tx.Exec("DELETE FROM new_bond_listen_group WHERE group_id = ?", groupID)
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func BondDataExists(securityCode string) (bool, error) {
|
||||
db := sqlite3.GetDB()
|
||||
var count int
|
||||
if err := db.Get(&count, "SELECT COUNT(*) FROM BondData WHERE SecurityCode = ?", securityCode); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func AddBondData(data BondData) error {
|
||||
tx, err := sqlite3.GetTran()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
query := `INSERT INTO BondData (
|
||||
SecurityCode, SecuCode, TradeMarket, SecurityNameAbbr, DelistDate,
|
||||
ListingDate, ConvertStockCode, BondExpire, Rating, ValueDate,
|
||||
IssueYear, CeaseDate, ExpireDate, PayInterestDay, InterestRateExplain,
|
||||
BondCombineCode, ActualIssueScale, IssuePrice, Remark, ParValue,
|
||||
IssueObject, RedeemType, ExecuteReasonHS, NoticeDateHS, NoticeDateSH,
|
||||
ExecutePriceHS, ExecutePriceSH, RecordDateSH, ExecuteStartDateSH, ExecuteStartDateHS,
|
||||
ExecuteEndDate, CorreCode, CorreCodeNameAbbr, PublicStartDate, CorreCodeO,
|
||||
CorreCodeNameAbbrO, BondStartDate, SecurityStartDate, SecurityShortName, FirstPerPreplacing,
|
||||
OnlineGeneralAAU, OnlineGeneralLWR, InitialTransferPrice, TransferEndDate, TransferStartDate,
|
||||
ResaleClause, RedeemClause, PartyName, ConvertStockPrice, TransferPrice,
|
||||
TransferValue, CurrentBondPrice, TransferPremiumRatio, ConvertStockPriceHQ, Market,
|
||||
ResaleTrigPrice, RedeemTrigPrice, PBVRatio, IBStartDate, IBEndDate,
|
||||
CashflowDate, CouponIR, ParamName, IssueType, ExecuteReasonSH,
|
||||
PaydayNew, CurrentBondPriceNew, IsConvertStock, IsRedeem, IsSellback,
|
||||
FirstProfit
|
||||
) VALUES (
|
||||
:SecurityCode, :SecuCode, :TradeMarket, :SecurityNameAbbr, :DelistDate,
|
||||
:ListingDate, :ConvertStockCode, :BondExpire, :Rating, :ValueDate,
|
||||
:IssueYear, :CeaseDate, :ExpireDate, :PayInterestDay, :InterestRateExplain,
|
||||
:BondCombineCode, :ActualIssueScale, :IssuePrice, :Remark, :ParValue,
|
||||
:IssueObject, :RedeemType, :ExecuteReasonHS, :NoticeDateHS, :NoticeDateSH,
|
||||
:ExecutePriceHS, :ExecutePriceSH, :RecordDateSH, :ExecuteStartDateSH, :ExecuteStartDateHS,
|
||||
:ExecuteEndDate, :CorreCode, :CorreCodeNameAbbr, :PublicStartDate, :CorreCodeO,
|
||||
:CorreCodeNameAbbrO, :BondStartDate, :SecurityStartDate, :SecurityShortName, :FirstPerPreplacing,
|
||||
:OnlineGeneralAAU, :OnlineGeneralLWR, :InitialTransferPrice, :TransferEndDate, :TransferStartDate,
|
||||
:ResaleClause, :RedeemClause, :PartyName, :ConvertStockPrice, :TransferPrice,
|
||||
:TransferValue, :CurrentBondPrice, :TransferPremiumRatio, :ConvertStockPriceHQ, :Market,
|
||||
:ResaleTrigPrice, :RedeemTrigPrice, :PBVRatio, :IBStartDate, :IBEndDate,
|
||||
:CashflowDate, :CouponIR, :ParamName, :IssueType, :ExecuteReasonSH,
|
||||
:PaydayNew, :CurrentBondPriceNew, :IsConvertStock, :IsRedeem, :IsSellback,
|
||||
:FirstProfit
|
||||
)`
|
||||
|
||||
_, err = tx.NamedExec(query, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetGroupListens() ([]int, error) {
|
||||
db := sqlite3.GetDB()
|
||||
var groupIDs []int
|
||||
if err := db.Select(&groupIDs, "SELECT group_id FROM new_bond_listen_group"); err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return groupIDs, nil
|
||||
}
|
||||
|
||||
func RoundCheckNewBond() {
|
||||
time.Sleep(5 * time.Second)
|
||||
for !action.ActionManager.Started() {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
once := true
|
||||
for {
|
||||
if !once {
|
||||
time.Sleep(5 * time.Minute)
|
||||
}
|
||||
bonds, err := GetBondsData()
|
||||
if bonds == nil || err != nil {
|
||||
fmt.Println("Error getting bonds data:", err)
|
||||
continue
|
||||
}
|
||||
groups, err := GetGroupListens()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting group listens:", err)
|
||||
continue
|
||||
}
|
||||
for _, bond := range bonds {
|
||||
exists, err := BondDataExists(bond.SecurityCode)
|
||||
if err != nil {
|
||||
fmt.Println("Error checking bond data exists:", err)
|
||||
continue
|
||||
}
|
||||
if !exists && bond.ListingDate == nil {
|
||||
for _, group := range groups {
|
||||
msg := model.Reply{
|
||||
ReplyMsg: fmt.Sprintf("号外号外,%s开始申购了", bond.SecurityNameAbbr),
|
||||
ReferOriginMsg: false,
|
||||
FromMsg: model.Message{
|
||||
GroupInfo: model.GroupInfo{
|
||||
GroupId: int64(group),
|
||||
},
|
||||
},
|
||||
}
|
||||
action.ActionManager.SendMsg(msg)
|
||||
}
|
||||
}
|
||||
AddBondData(bond)
|
||||
}
|
||||
once = false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user