//circular strategy func (circular *circularStrategy) Tick(records []Record) bool { if circular.PrevClosePrice == lastPrice { return false } basePrice, err := strconv.ParseFloat(Option["basePrice"], 64) if err != nil { logger.Debugln("config item basePrice is not float") return false } fluctuation, err := strconv.ParseFloat(Option["fluctuation"], 64) if err != nil { logger.Debugln("config item fluctuation is not float") return false } circular.PrevClosePrice = lastPrice logger.Infof("lastPrice %0.02f\n", lastPrice) if lastPrice >= basePrice+fluctuation { Sell() } else if lastPrice <= basePrice-fluctuation { Buy() } //do sell when price is below stoploss point processStoploss(lastPrice) processTimeout() return true }
func TriggerPrice(price float64) error { lowest_price, err := strconv.ParseFloat(Option["lowest_price"], 64) if err != nil { logger.Debugln("config item lowest_price is not float") return err } highest_price, err := strconv.ParseFloat(Option["highest_price"], 64) if err != nil { logger.Debugln("config item highest_price is not float") return err } var alert string if Option["disable_email"] != "1" { if price < lowest_price { alert = fmt.Sprintf("价格 %f 低于设定的阀值 %f", price, Option["lowest_price"]) } else if price > highest_price { alert = fmt.Sprintf("价格 %f 超过设定的阀值 %f", price, Option["highest_price"]) } if alert != "" { SendAlertEmail(Option["to_email"], alert) } } return nil }
func decrUserActiveWeight() { logger.Debugln("start decr user active weight...") loginTime := time.Now().Add(-72 * time.Hour) userList, err := service.FindNotLoginUsers(loginTime.Format(util.TIME_LAYOUT_OFTEN)) if err != nil { logger.Errorln("获取最近未登录用户失败:", err) return } logger.Debugln("need dealing users:", len(userList)) for _, user := range userList { divide := 5 lastLoginTime, err := util.TimeParseOften(user.LoginTime) if err == nil { hours := (loginTime.Sub(lastLoginTime) / 24).Hours() if hours < 24 { divide = 2 } else if hours < 48 { divide = 3 } else if hours < 72 { divide = 4 } } logger.Debugln("decr user weight, username:"******"divide:", divide) service.DecrUserWeight("username='******'", divide) } logger.Debugln("end decr user active weight...") }
// just f**k the huobi old shit bug func parse_topsell(topsells map[string]interface{}, topsells_data *[5]Top_buy_sell) bool { index := 4 for k, v := range topsells { switch vt := v.(type) { case map[string]interface{}: logger.Debugln(k, " is a map:") logger.Debugf("topsells[%s]\n", k) for ik, iv := range vt { logger.Debugln(ik, iv) switch ik { case "price": topsells_data[index].Price = util.InterfaceToFloat64(iv) case "amount": topsells_data[index].Amount = util.InterfaceToFloat64(iv) case "level": topsells_data[index].Level = util.InterfaceToFloat64(iv) case "accu": topsells_data[index].Accu = util.InterfaceToFloat64(iv) } } index-- default: logger.Errorln(k, v) logger.Fatalln("don't know the type, crash!") return false } } return true }
func ReadCSV(path string) (data [][]string) { file, err := os.Open(path) if err != nil { logger.Debugln("Error:", err) return } defer file.Close() reader := csv.NewReader(file) data, err2 := reader.ReadAll() if err2 != nil { logger.Debugln("Error:", err2) return } return data //flag := 0 //for { // record, err := reader.Read() // if err == io.EOF { // break // } else if err != nil { // logger.Debugln("Error:", err) // return // } // data[flag] = record // flag++ // //fmt.Println(record) // record has the type []string //} }
func (w *Huobi) TradeDelegationAnalyze(body string) bool { logger.Debugln("TradeDelegationAnalyze start....") var ids []string for _, pat := range strings.Split(body, `">撤单`) { if len(pat) == 0 { // Empty strings such as from a trailing comma can be ignored. continue } patLev := strings.Split(pat, "a=cancel&id=") if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 { logger.Debugln("parse end") break } logger.Debugln(patLev[1]) ids = append(ids, patLev[1]) } logger.Debugln(ids) w.TradeCancel1stPage(ids) logger.Debugln("TradeDelegationAnalyze end-----") return true }
func (w *Huobi) checkAccount(a, price, amount string) bool { btc, cny := w.get_account_info() FPrice, err := strconv.ParseFloat(price, 64) if err != nil { logger.Debugln("price is not float") return false } FAmount, err := strconv.ParseFloat(amount, 64) if err != nil { logger.Debugln("amount is not float") return false } if a == "do_buy" { if float64(cny) < FPrice*FAmount { return false } } else { if float64(btc) < FAmount { return false } } return true }
func EngineHandler(rw http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) msgtype := vars["msgtype"] if req.Method != "POST" && msgtype == "" { // 获取用户信息 err := config.LoadOption() if err != nil { logger.Errorln(err) fmt.Fprint(rw, `{"errno": 1, "msg":"`, "读取引擎配置数据失败", `"}`) return } // 设置模板数据 filter.SetData(req, map[string]interface{}{"config": config.Option}) req.Form.Set(filter.CONTENT_TPL_KEY, "/template/trade/engine.html") return } else if req.Method != "POST" && msgtype == "ajax" { Option_json, err := json.Marshal(config.Option) if err != nil { logger.Errorln(err) fmt.Fprint(rw, `{"errno": 1, "msg":"`, "读取引擎配置数据失败", `"}`) } else { fmt.Fprint(rw, string(Option_json)) } return } else { logger.Debugln("===[", req.FormValue("disable_trading"), "]") if req.FormValue("disable_trading") == "on" { config.Option["disable_trading"] = "1" } else { config.Option["disable_trading"] = "0" } logger.Debugln("===[", req.FormValue("disable_backtesting"), "]") if req.FormValue("disable_backtesting") == "on" { config.Option["disable_backtesting"] = "1" } else { config.Option["disable_backtesting"] = "0" } config.Option["tick_interval"] = req.FormValue("tick_interval") config.Option["shortEMA"] = req.FormValue("shortEMA") config.Option["longEMA"] = req.FormValue("longEMA") config.Option["tradeAmount"] = req.FormValue("tradeAmount") config.Option["totalHour"] = req.FormValue("totalHour") // 更新个人信息 err := config.SaveOption() if err != nil { fmt.Fprint(rw, `{"errno": 1, "msg":"`, "写入引擎配置数据失败", `"}`) return } fmt.Fprint(rw, `{"errno": 0, "msg":"更新引擎配置成功!"}`) } }
func (w *Huobi) TradeCancel1stPage(ids []string) bool { logger.Debugln("TradeCancel1stPage start....") for _, id := range ids { w.TradeCancel(id) } logger.Debugln("TradeCancel1stPage end-----") return true }
func (this *LoginFilter) PreFilter(rw http.ResponseWriter, req *http.Request) bool { logger.Debugln("LoginFilter PreFilter...") if _, ok := CurrentUser(req); !ok { logger.Debugln("需要登录") // 没有登录 util.Redirect(rw, req, "/account/login") return false } return true }
func (w *Huobi) trade(emaShort, emaLong []float64, EMAMinThreshold float64, TresholdLevel int, length int, tradeOnlyAfterSwitch int, tradeAmount string) { currentTrend := getTrendAtIndex(emaShort, emaLong, EMAMinThreshold, TresholdLevel, length-1) logger.Debugln("currentTrend is ", currentTrend) if currentTrend > 1 { // Trend is up if currentTrend == 3 { // Trend is up, also according to the "Buy after X samples"-setting if (tradeOnlyAfterSwitch == 1) && (w.latestSolidTrend == 3) { // tradeOnlyAfterSwitch==true but the trend has not switched: Don't trade logger.Debugln("Trend has not switched (still up). The setting \"tradeOnlyAfterSwitch==true\", so do not trade...") return } w.latestSolidTrend = 3 if Option["disable_trading"] == "1" { logger.Debugln("Simulted BUY (Simulation only: no trade was made)") } else { logger.Infoln("Trend has switched, 探测到买入点") go service.TriggerTrender("探测到买入点") w.Do_buy(w.getTradePrice("buy"), tradeAmount) } //logger.Infoln("Trend is up, but no " + currency + " to spend..."); } else { logger.Debugf("Trend is up, but not for long enough (needs to be \"up\" for at least %d samples)\n", TresholdLevel) } } else if currentTrend < -1 { // Trend is down if currentTrend == -3 { // Trend is down, also according to the "Sell after X samples"-setting if (tradeOnlyAfterSwitch == 1) && (w.latestSolidTrend == -3) { // tradeOnlyAfterSwitch==true but the trend has not switched: Don't trade logger.Debugln("Trend has not switched (still down). The setting \"tradeOnlyAfterSwitch==true\", so do not trade...") return } w.latestSolidTrend = -3 if Option["disable_trading"] == "1" { logger.Infoln("Simulted SELL (Simulation only: no trade was made)") } else { logger.Infoln("Trend has switched, 探测到卖出点") go service.TriggerTrender("探测到卖出点") w.Do_sell(w.getTradePrice("sell"), tradeAmount) } //logger.Infoln("Trend is down, but no BTC to sell..."); } else { logger.Debugf("Trend is down, but not for long enough (needs to be \"down\" for at least t %d samples)\n", TresholdLevel) } } else { logger.Debugln("Trend is undefined/weak") } }
func (this *LoginFilter) PreFilter(rw http.ResponseWriter, req *http.Request) bool { logger.Debugln("LoginFilter PreFilter...") if _, ok := CurrentUser(req); !ok { logger.Debugln("需要登录") // 支持跳转回原来访问的页面 NewFlash(rw, req).AddFlash(req.RequestURI, "uri") util.Redirect(rw, req, "/account/login") return false } return true }
func SendAlertEmail(receiver, alert string) error { // Set up authentication information. auth := smtp.PlainAuth("", SecretOption["smtp_username"], SecretOption["smtp_password"], SecretOption["smtp_host"]) from := mail.Address{"BTCRobot监控中心", SecretOption["smtp_username"]} to := mail.Address{"收件人", receiver} title := "BTCRobot来电--->" + alert body := ` <html> <body> <h3> %s </h3> <p> 捐助BTC,支持开发<span style="font-size: 80%"><a href="bitcoin:1NDnnWCUu926z4wxA3sNBGYWNQD3mKyes8">1NDnnWCUu926z4wxA3sNBGYWNQD3mKyes8</a></span> </p> </body> </html> ` body = fmt.Sprintf(body, alert) header := make(map[string]string) header["From"] = from.String() header["To"] = to.String() header["Subject"] = encodeRFC2047(title) header["MIME-Version"] = "1.0" header["Content-Type"] = "text/html; charset=\"utf-8\"" header["Content-Transfer-Encoding"] = "base64" message := "" for k, v := range header { message += fmt.Sprintf("%s: %s\r\n", k, v) } message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body)) logger.Debugln("Try sending Mail to", to) // Connect to the server, authenticate, set the sender and recipient, // and send the email all in one step. err := smtp.SendMail( SecretOption["smtp_addr"], auth, from.Address, []string{to.Address}, []byte(message)) if err != nil { logger.Infoln("Send Mail to", to, "error:", err) return err } logger.Debugln("Send Mail to", to, "Successfully") return nil }
func doTradeDelegation() { huobi := huobiapi.NewHuobi() logger.Infoln("doTradeDelegation start....") if huobi.Login() == true { logger.Debugln("Login successfully.") huobi.TradeDelegation() } else { logger.Debugln("Login failed.") } logger.Infoln("doTradeDelegation end-----") }
// FindAll 查找多条数据 func (this *Dao) FindAll(selectCol ...string) (*sql.Rows, error) { sort.Sort(sort.StringSlice(selectCol)) this.selectCols = "`" + strings.Join(selectCol, "`,`") + "`" strSql := util.SelectSql(this) logger.Debugln("FindAll sql:", strSql) logger.Debugln("FindAll bind params:", this.whereVal) err := this.Open() if err != nil { return nil, err } defer this.Close() return this.Query(strSql, this.whereVal...) }
//本地服务器测试函数 func WechatTest(rw http.ResponseWriter, req *http.Request) { //没有相应的OPENID则为其注册一个 if !service.OpenidExists("dsgdsgdgsg") { test := service.CreateWechatPlayer("dsgdsgdgsg") if test { logger.Debugln("用户注册成功") } } else { logger.Debugln("用户已经存在") } }
func doTradeDelegation() { huobi := huobiapi.NewHuobi() logger.Infoln("doTradeDelegation start....") if huobi.Login() == true { console.SetColor(console.FOREGROUND_GREEN) logger.Debugln("Login successfully.") huobi.TradeDelegation() } else { logger.Debugln("Login failed.") } logger.Infoln("doTradeDelegation end-----") }
func (this *views) Flush() { logger.Debugln("start views flush") this.locker.Lock() defer this.locker.Unlock() // TODO:量大时,考虑copy一份,然后异步 入库,以免堵塞 锁 太久 for _, view := range this.data { view.flush() } this.data = make(map[string]*view) this.users = make(map[string]bool) logger.Debugln("end views flush") }
func getSellPrice() (price string, nPrice float64, warning string) { //compute the price slippage, err := strconv.ParseFloat(Option["slippage"], 64) if err != nil { logger.Debugln("config item slippage is not float") slippage = 0.01 } sell1, _, ret := getOrderPrice() if !ret { return } nPrice = sell1 * (1 - slippage*0.01) if !isStoploss && Option["discipleMode"] == "1" { if nPrice < PrevBuyPirce { discipleValue, err := strconv.ParseFloat(Option["discipleValue"], 64) if err != nil { logger.Errorln("config item discipleValue is not float") discipleValue = 0.01 } nPrice = PrevBuyPirce + discipleValue } } price = fmt.Sprintf("%f", nPrice) warning += "---->限价单" + price return }
// 持久化 entity 到数据库 func (this *Dao) Persist(entity interface{}) error { strSql, args, err := genPersistParams(entity) if err != nil { logger.Errorln("Persist error:", err) return err } logger.Debugln("Persist sql:", strSql, ";args:", args) err = this.Open() if err != nil { return err } defer this.Close() result, err := this.Exec(strSql, args...) if err != nil { return err } affected, err := result.RowsAffected() if err != nil { return err } logger.Debugf("成功更新了`%s`表 %d 条记录", this.tablename, affected) return nil }
// PreFilter 执行 handler 之前的过滤方法 func (this *SensitiveFilter) PreFilter(rw http.ResponseWriter, req *http.Request) bool { logger.Debugln("SensitiveFilter PreFilter...") content := req.FormValue("content") title := req.FormValue("title") if title == "" && content == "" { return true } curUser, _ := CurrentUser(req) // 标题特殊处理 for _, s := range titleSensitives { if util.HasSensitiveChar(title, s) { // 把账号冻结 service.UpdateUserStatus(curUser["uid"].(int), model.StatusFreeze) logger.Infoln("user="******"uid"], "publish ad, title=", title, ";content=", content, ". freeze") return false } } sensitive := config.Config["sensitive"] if util.HasSensitive(title, sensitive) || util.HasSensitive(content, sensitive) { // 把账号冻结 service.UpdateUserStatus(curUser["uid"].(int), model.StatusFreeze) logger.Infoln("user="******"uid"], "publish ad, title=", title, ";content=", content, ". freeze") return false } return true }
// Increment 增加/减少 某个字段的值 func (this *Dao) Increment(field string, num int) error { if num == 0 { return errors.New("dao Increment(`num`不能为0)") } where := this.where if where != "" { where = "WHERE " + where } setClause := fmt.Sprintf("`%s`=`%s`", field, field) if num > 0 { setClause += fmt.Sprintf("+%d", num) } else { setClause += fmt.Sprintf("-%d", num) } strSql := fmt.Sprintf("UPDATE `%s` SET %s %s", this.tablename, setClause, where) logger.Debugln("Increment sql:", strSql) err := this.Open() if err != nil { return err } defer this.Close() result, err := this.Exec(strSql, this.whereVal...) if err != nil { return err } affected, err := result.RowsAffected() if err != nil { return err } if affected == 0 { return errors.New("dao Increment 没有更新任何数据!") } logger.Debugf("成功 increment `%s`表 %d 条记录", this.tablename, affected) return nil }
func (this *TopicNode) FindAll(selectCol ...string) ([]*TopicNode, error) { if len(selectCol) == 0 { selectCol = util.MapKeys(this.colFieldMap()) } rows, err := this.Dao.FindAll(selectCol...) if err != nil { return nil, err } // TODO: nodeList := make([]*TopicNode, 0, 10) logger.Debugln("selectCol", selectCol) colNum := len(selectCol) for rows.Next() { node := NewTopicNode() colFieldMap := node.colFieldMap() scanInterface := make([]interface{}, 0, colNum) for _, column := range selectCol { scanInterface = append(scanInterface, colFieldMap[column]) } err = rows.Scan(scanInterface...) if err != nil { logger.Errorln("TopicNode FindAll Scan Error:", err) continue } nodeList = append(nodeList, node) } return nodeList, nil }
// Find 查找单条数据 // colFieldMap 数据库表中列对应go中对象的字段 func (this *Dao) Find(colFieldMap map[string]interface{}, selectCol ...string) error { colNum := len(selectCol) if colNum == 0 || (colNum == 1 && selectCol[0] == "*") { selectCol = util.MapKeys(colFieldMap) } sort.Sort(sort.StringSlice(selectCol)) this.selectCols = "`" + strings.Join(selectCol, "`,`") + "`" strSql := util.SelectSql(this) logger.Debugln("Find sql:", strSql) err := this.Open() if err != nil { return err } defer this.Close() row := this.QueryRow(strSql, this.whereVal...) scanInterface := make([]interface{}, 0, colNum) for _, column := range selectCol { scanInterface = append(scanInterface, colFieldMap[column]) } err = row.Scan(scanInterface...) if err == sql.ErrNoRows { logger.Infoln("Find", strSql, ":no result ret") return nil } return err }
func (w *Huobi) AnalyzeMinuteLine(filename string, content string) bool { //logger.Infoln(content) logger.Debugln(filename) MinuteRecords := ParseMinuteCSV(filename) var xData []string var yData []float64 for _, v := range MinuteRecords { xData = append(xData, v.Time) yData = append(yData, v.Price) } if Config["env"] == "test" { price, ret := w.getNewPrice() if ret == false { return false } xData = append(xData, "now") yData = append(yData, price) } w.xData = xData w.yData = yData if Config["env"] == "test" { w.do2Percent(xData, yData) return true } else { w.doEMA(xData, yData) return true } }
func uploadLocalFile(localFile, key string) (err error) { InitQiniu() var ret io.PutRet var extra = &io.PutExtra{ // Params: params, // MimeType: mieType, // Crc32: crc32, // CheckCrc: CheckCrc, } // ret 变量用于存取返回的信息,详情见 io.PutRet // uptoken 为业务服务器生成的上传口令 // key 为文件存储的标识(文件名) // localFile 为本地文件名 // extra 为上传文件的额外信息,详情见 io.PutExtra,可选 err = io.PutFile(nil, &ret, uptoken, key, localFile, extra) if err != nil { //上传产生错误 logger.Errorln("io.PutFile failed:", err) return } //上传成功,处理返回值 logger.Debugln(ret.Hash, ret.Key) return }
func parse_buy_sell(sells_buys []interface{}, sells_buys_data *[10]SellBuy) bool { for k, v := range sells_buys { switch vt := v.(type) { case map[string]interface{}: logger.Debugln(k, " is a map:") logger.Debugf("sells/buys[%d]\n", k) for ik, iv := range vt { switch ik { case "price": sells_buys_data[k].Price = util.InterfaceToFloat64(iv) case "level": sells_buys_data[k].Level = util.InterfaceToFloat64(iv) case "amount": sells_buys_data[k].Amount = util.InterfaceToFloat64(iv) } } default: logger.Errorln(k, v) logger.Fatalln("don't know the type, crash!") return false } } return true }
// 登录 // uri : /account/login func LoginHandler(rw http.ResponseWriter, req *http.Request) { username := req.FormValue("username") if username == "" || req.Method != "POST" { req.Form.Set(filter.CONTENT_TPL_KEY, "/template/login.html") return } // 处理用户登录 passwd := req.FormValue("passwd") userLogin, err := service.Login(username, passwd) if err != nil { req.Form.Set(filter.CONTENT_TPL_KEY, "/template/login.html") filter.SetData(req, map[string]interface{}{"username": username, "error": err.Error()}) return } logger.Debugf("remember_me is %q\n", req.FormValue("remember_me")) // 登录成功,种cookie setCookie(rw, req, userLogin.Username) // 支持跳转到源页面 uri := "/" values := filter.NewFlash(rw, req).Flashes("uri") if values != nil { uri = values[0].(string) } logger.Debugln("uri===", uri) util.Redirect(rw, req, uri) }
func testKLineAPI(done chan bool) { ticker := time.NewTicker(time.Millisecond * 2000) huobi := huobiapi.NewHuobi() huobi.Peroid, _ = strconv.Atoi(Option["tick_interval"]) slippage, err := strconv.ParseFloat(Config["slippage"], 64) if err != nil { logger.Debugln("config item slippage is not float") slippage = 0 } huobi.Slippage = slippage go func() { for _ = range ticker.C { if huobi.Peroid == 1 { huobi.TradeKLineMinute() } else { huobi.TradeKLinePeroid(huobi.Peroid) } } }() time.Sleep(time.Millisecond * 24 * 60 * 60 * 1000) ticker.Stop() fmt.Println("Ticker stopped") done <- true }
func parse_trade(trades []interface{}, trades_data *[60]Trade) bool { for k, v := range trades { switch vt := v.(type) { case map[string]interface{}: logger.Debugln(k, " is a map:") logger.Debugf("trades[%d]\n", k) for ik, iv := range vt { switch ik { case "time": trades_data[k].Time = iv.(string) case "price": trades_data[k].Price = util.InterfaceToFloat64(iv) case "amount": trades_data[k].Amount = util.InterfaceToFloat64(iv) case "type": trades_data[k].Type = iv.(string) } } default: logger.Errorln(k, v) logger.Fatalln("don't know the type, crash!") return false } } return true }