qq_bot/handler/newbond/service.go
2024-11-27 01:15:45 +08:00

268 lines
8.6 KiB
Go

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&quoteColumns=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&quoteType=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
}
}