func Sell() string { if PrevTrade == "sell" { return "0" } // compute the price price, _, warning := getSellPrice() // compute the amount Available_coin := GetAvailable_coin() if Available_coin < 0.01 { warning = "没有足够的币" logger.Infoln(warning) PrevTrade = "sell" PrevBuyPirce = 0 return "0" } amount := Option["tradeAmount"] nAmount, err := strconv.ParseFloat(amount, 64) if err != nil { logger.Infoln("amount is not float") return "0" } if nAmount > Available_coin { nAmount = Available_coin amount = fmt.Sprintf("%02f", nAmount) } sellID := sell(price, amount) if sellID == "-1" { warning += " [模拟]" } else if sellID == "0" { warning += "[委托失败]" } else { warning += "[委托成功]" + sellID } logger.Infoln(warning) var coin string if Option["symbol"] == "btc_cny" { coin = "比特币" } else { coin = "莱特币" } if sellID != "0" { if !GetBacktest() { logger.Tradef("在%s,根据策略%s周期%s,以价格%s卖出%s个%s\n", Option["tradecenter"], Option["strategy"], Option["tick_interval"], price, amount, coin) go email.TriggerTrender(warning) } else { t := time.Unix(GetBtTime(), 0) logger.Backtestf("%s 在simulate,根据策略%s周期%s,以价格%s卖出%s个%s\n", t.Format("2006-01-02 15:04:05"), Option["strategy"], Option["tick_interval"], price, amount, coin) } } return sellID }
func Buy() string { if PrevTrade == "buy" { return "0" } //init isStoploss = false //compute the price price, nPrice, warning := getBuyPrice() //compute the amount amount := Option["tradeAmount"] nAmount, err := strconv.ParseFloat(amount, 64) if err != nil { logger.Infoln("amount is not float") return "0" } Available_cny := GetAvailable_cny() if Available_cny < nPrice*nAmount { var nMinTradeAmount float64 nAmount = Available_cny / nPrice symbol := Option["symbol"] if symbol == "btc_cny" { nMinTradeAmount = 0.1 } else { nMinTradeAmount = 0.01 } if nAmount < nMinTradeAmount { warning += "没有足够的法币余额" logger.Infoln(warning) PrevTrade = "buy" PrevBuyPirce = nPrice return "0" } amount = fmt.Sprintf("%02f", nAmount) } warning += "---->数量" + amount buyID := buy(price, amount) if buyID == "-1" { warning += " [模拟]" } else if buyID == "0" { warning += "[委托失败]" } else { warning += "[委托成功]" + buyID } logger.Infoln(warning) go email.TriggerTrender(warning) return buyID }
func Sell() string { if PrevTrade == "sell" { return "0" } //compute the price price, _, warning := getSellPrice() //compute the amount Available_coin := GetAvailable_coin() if Available_coin < 0.01 { warning = "没有足够的币" logger.Infoln(warning) PrevTrade = "sell" PrevBuyPirce = 0 return "0" } amount := Option["tradeAmount"] nAmount, err := strconv.ParseFloat(amount, 64) if err != nil { logger.Infoln("amount is not float") return "0" } if nAmount > Available_coin { nAmount = Available_coin amount = fmt.Sprintf("%02f", nAmount) } sellID := sell(price, amount) if sellID == "-1" { warning += " [模拟]" } else if sellID == "0" { warning += "[委托失败]" } else { warning += "[委托成功]" + sellID } logger.Infoln(warning) go email.TriggerTrender(warning) return sellID }
func SecretHandler(rw http.ResponseWriter, req *http.Request) { if !Basic(rw, req) { return } vars := mux.Vars(req) msgtype := vars["msgtype"] if req.Method != "POST" && msgtype == "" { // 获取用户信息 err := config.LoadSecretOption() if err != nil { fmt.Fprint(rw, `{"errno": 1, "error":"`, "读取秘钥配置数据失败", `"}`) return } // 设置模板数据 filter.SetData(req, map[string]interface{}{"config": config.SecretOption}) req.Form.Set(filter.CONTENT_TPL_KEY, "/template/trade/secret.html") return } else { config.SecretOption["username"] = req.FormValue("username") config.SecretOption["password"] = req.FormValue("password") config.SecretOption["huobi_access_key"] = req.FormValue("huobi_access_key") config.SecretOption["huobi_secret_key"] = req.FormValue("huobi_secret_key") config.SecretOption["ok_partner"] = req.FormValue("ok_partner") config.SecretOption["ok_secret_key"] = req.FormValue("ok_secret_key") config.SecretOption["smtp_username"] = req.FormValue("smtp_username") config.SecretOption["smtp_password"] = req.FormValue("smtp_password") config.SecretOption["smtp_host"] = req.FormValue("smtp_host") config.SecretOption["smtp_addr"] = req.FormValue("smtp_addr") // 更新个人信息 err := config.SaveSecretOption() if err != nil { fmt.Fprint(rw, `{"errno": 1, "error":"`, "写入秘钥配置数据失败", `"}`) return } fmt.Fprint(rw, `{"errno": 0, "msg":"更新秘钥配置成功!"}`) go email.TriggerTrender("btcrobot测试邮件,您能收到这封邮件说明您的SMTP配置成功,来自星星的机器人") } }
func webui() { m := martini.Classic() m.Get("/secret", func() string { // show something err := LoadSecretOption() if err != nil { logger.Errorln(err) return `{"errno": 1, "msg":", "读取秘钥配置数据失败"}` } Option_json, err := json.Marshal(SecretOption) if err != nil { logger.Errorln(err) return `{"errno": 1, "msg":", "解析秘钥配置数据失败"}` } return string(Option_json) }) m.Post("/secret", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini SecretOption["username"] = req.FormValue("username") SecretOption["password"] = req.FormValue("password") SecretOption["bitvc_email"] = req.FormValue("bitvc_email") SecretOption["bitvc_password"] = req.FormValue("bitvc_password") SecretOption["huobi_access_key"] = req.FormValue("huobi_access_key") SecretOption["huobi_secret_key"] = req.FormValue("huobi_secret_key") SecretOption["smtp_username"] = req.FormValue("smtp_username") SecretOption["smtp_password"] = req.FormValue("smtp_password") SecretOption["smtp_host"] = req.FormValue("smtp_host") SecretOption["smtp_addr"] = req.FormValue("smtp_addr") SecretOption["OKCoinAPIkey"] = req.FormValue("OKCoinAPIkey") SecretOption["ok_partner"] = req.FormValue("ok_partner") SecretOption["ok_secret_key"] = req.FormValue("ok_secret_key") SecretOption["ok_partner1"] = req.FormValue("ok_partner1") SecretOption["ok_secret_key1"] = req.FormValue("ok_secret_key1") SecretOption["ok_partner2"] = req.FormValue("ok_partner2") SecretOption["ok_secret_key2"] = req.FormValue("ok_secret_key2") SecretOption["ok_partner3"] = req.FormValue("ok_partner3") SecretOption["ok_secret_key3"] = req.FormValue("ok_secret_key3") SecretOption["ok_partner4"] = req.FormValue("ok_partner4") SecretOption["ok_secret_key4"] = req.FormValue("ok_secret_key4") SecretOption["ok_partner5"] = req.FormValue("ok_partner5") SecretOption["ok_secret_key5"] = req.FormValue("ok_secret_key5") SecretOption["ok_partner6"] = req.FormValue("ok_partner6") SecretOption["ok_secret_key6"] = req.FormValue("ok_secret_key6") SecretOption["ok_partner7"] = req.FormValue("ok_partner7") SecretOption["ok_secret_key7"] = req.FormValue("ok_secret_key7") SecretOption["ok_partner8"] = req.FormValue("ok_partner8") SecretOption["ok_secret_key8"] = req.FormValue("ok_secret_key8") SecretOption["ok_partner9"] = req.FormValue("ok_partner9") SecretOption["ok_secret_key9"] = req.FormValue("ok_secret_key9") SecretOption["ok_partner10"] = req.FormValue("ok_partner10") SecretOption["ok_secret_key10"] = req.FormValue("ok_secret_key10") // 更新个人信息 err := SaveSecretOption() if err != nil { fmt.Fprint(res, "写入秘钥配置数据失败") return } fmt.Fprint(res, "更新秘钥配置成功!") go email.TriggerTrender("btcrobot测试邮件,您能收到这封邮件说明您的SMTP配置成功,来自星星的机器人") return }) m.Get("/engine", func() string { // show something err := LoadOption() if err != nil { logger.Errorln(err) return `{"errno": 1, "msg":", "读取引擎配置数据失败"}` } Option_json, err := json.Marshal(Option) if err != nil { logger.Errorln(err) return `{"errno": 1, "msg":", "解析引擎配置数据失败"}` } return string(Option_json) }) m.Post("/engine", func(res http.ResponseWriter, req *http.Request) { if req.FormValue("enable_trading") == "on" { Option["enable_trading"] = "1" } else { Option["enable_trading"] = "0" } if req.FormValue("discipleMode") == "on" { Option["discipleMode"] = "1" } else { Option["discipleMode"] = "0" } Option["discipleValue"] = req.FormValue("discipleValue") // open传递过来的是“on”或没传递 if req.FormValue("enable_email") == "on" { Option["enable_email"] = "1" } else { Option["enable_email"] = "0" } Option["to_email"] = req.FormValue("to_email") Option["tick_interval"] = req.FormValue("tick_interval") Option["datacenter"] = req.FormValue("datacenter") Option["tradecenter"] = req.FormValue("tradecenter") Option["symbol"] = req.FormValue("symbol") Option["strategy"] = req.FormValue("strategy") Option["shortEMA"] = req.FormValue("shortEMA") Option["longEMA"] = req.FormValue("longEMA") Option["signalPeriod"] = req.FormValue("signalPeriod") Option["tradeAmount"] = req.FormValue("tradeAmount") Option["slippage"] = req.FormValue("slippage") Option["totalHour"] = req.FormValue("totalHour") Option["buyThreshold"] = req.FormValue("buyThreshold") Option["sellThreshold"] = req.FormValue("sellThreshold") Option["MACDbuyThreshold"] = req.FormValue("MACDbuyThreshold") Option["MACDsellThreshold"] = req.FormValue("MACDsellThreshold") Option["basePrice"] = req.FormValue("basePrice") Option["fluctuation"] = req.FormValue("fluctuation") Option["stoploss"] = req.FormValue("stoploss") // 更新个人信息 err := SaveOption() if err != nil { fmt.Fprint(res, "写入引擎配置数据失败") return } fmt.Fprint(res, "更新引擎配置成功!") }) m.Get("/trade", func() string { // show something LoadTrade() err := LoadTrade() if err != nil { logger.Errorln(err) return `{"errno": 1, "msg":", "读取Trade配置数据失败"}` } Option_json, err := json.Marshal(TradeOption) if err != nil { logger.Errorln(err) return `{"errno": 1, "msg":", "解析引擎配置数据失败"}` } return string(Option_json) }) m.Post("/trade", func(res http.ResponseWriter, req *http.Request) { msgtype := req.FormValue("msgtype") var nbuyprice, nbuytotalamount, nbuyinterval, nmaxbuyamountratio float64 var nbuytimes int var nsellprice, nselltotalamount, nsellinterval, nmaxsellamountratio float64 var nselltimes int var err error if msgtype == "dobuy" { TradeOption["buyprice"] = req.FormValue("buyprice") TradeOption["buytotalamount"] = req.FormValue("buytotalamount") TradeOption["buyinterval"] = req.FormValue("buyinterval") TradeOption["buytimes"] = req.FormValue("buytimes") TradeOption["maxbuyamountratio"] = req.FormValue("maxbuyamountratio") nbuyprice, err = strconv.ParseFloat(Option["buyprice"], 64) if err != nil { logger.Errorln("config item buyprice is not float") return } nbuytotalamount, err = strconv.ParseFloat(Option["buytotalamount"], 64) if err != nil { logger.Errorln("config item numbuytotalamount is not float") return } nbuyinterval, err = strconv.ParseFloat(Option["buyinterval"], 64) if err != nil { logger.Errorln("config item buyinterval is not float") return } nbuytimes, err = strconv.Atoi(Option["buytimes"]) if err != nil { logger.Errorln("config item numbuytimes is not float") return } nmaxbuyamountratio, err = strconv.ParseFloat(Option["maxbuyamountratio"], 64) if err != nil { logger.Errorln("config item numbuytotalamount is not float") return } } else if msgtype == "dosell" { TradeOption["sellprice"] = req.FormValue("sellprice") TradeOption["selltotalamount"] = req.FormValue("selltotalamount") TradeOption["sellinterval"] = req.FormValue("sellinterval") TradeOption["selltimes"] = req.FormValue("selltimes") TradeOption["maxsellamountratio"] = req.FormValue("maxsellamountratio") nsellprice, err = strconv.ParseFloat(Option["sellprice"], 64) if err != nil { logger.Errorln("config item sellprice is not float") return } nselltotalamount, err = strconv.ParseFloat(Option["selltotalamount"], 64) if err != nil { logger.Errorln("config item selltotalamount is not float") return } nsellinterval, err = strconv.ParseFloat(Option["v"], 64) if err != nil { logger.Errorln("config item sellinterval is not float") return } nselltimes, err = strconv.Atoi(Option["selltimes"]) if err != nil { logger.Errorln("config item selltimes is not float") return } nmaxsellamountratio, err = strconv.ParseFloat(Option["maxsellamountratio"], 64) if err != nil { logger.Errorln("config item maxsellamountratio is not float") return } } else { fmt.Fprint(res, "无效的POST请求") } // 更新个人信息 err = SaveTrade() if err != nil { fmt.Fprint(res, "写入Trade配置数据失败") } var tradeAPI TradeAPI if Option["tradecenter"] == "huobi" { tradeAPI = huobi.NewHuobi() } else if Option["tradecenter"] == "okcoin" { tradeAPI = okcoin.NewOkcoin() } else { fmt.Fprint(res, "没有选择交易所名称") } var ret string var arrbuyTradePrice []float64 splitnbuyinterval := nbuyinterval / float64(nbuytimes) splitbuyTradeAmount := nbuytotalamount / float64(nbuytimes) if splitbuyTradeAmount/nbuytotalamount > nmaxbuyamountratio { return } if msgtype == "dobuy" { for i := 0; i < nbuytimes; i++ { warning := "oo, 买入buy In<----限价单" if i < nbuytimes/2 { arrbuyTradePrice[i] = nbuyprice - float64(i)*splitnbuyinterval } else { arrbuyTradePrice[i] = nbuyprice + float64((i-nbuytimes/2))*splitnbuyinterval } tradePrice := fmt.Sprintf("%f", arrbuyTradePrice[i]) strsplitTradeAmount := fmt.Sprintf("%f", splitbuyTradeAmount) ret = tradeAPI.Buy(tradePrice, strsplitTradeAmount) if ret != "0" { fmt.Fprint(res, "交易委托成功") } else { fmt.Fprint(res, "交易委托失败") } logger.Infoln(warning) } } var arrsellTradePrice []float64 splitnsellinterval := nsellinterval / float64(nselltimes) splitsellTradeAmount := nselltotalamount / float64(nselltimes) if splitsellTradeAmount/nselltotalamount > nmaxsellamountratio { return } if msgtype == "dosell" { for i := 0; i < nselltimes; i++ { warning := "oo, 卖出buy In<----限价单" if i < nselltimes/2 { arrsellTradePrice[i] = nsellprice - float64(i)*splitnsellinterval } else { arrsellTradePrice[i] = nsellprice + float64((i-nselltimes/2))*splitnsellinterval } tradePrice := fmt.Sprintf("%f", arrsellTradePrice[i]) strsplitTradeAmount := fmt.Sprintf("%f", splitbuyTradeAmount) ret = tradeAPI.Sell(tradePrice, strsplitTradeAmount) if ret != "0" { fmt.Fprint(res, "交易委托成功") } else { fmt.Fprint(res, "交易委托失败") } logger.Infoln(warning) } } }) m.Use(auth.Basic(SecretOption["username"], SecretOption["password"])) m.Use(martini.Static("./static")) m.Use(martini.Static("../static")) logger.Infoln(http.ListenAndServe(Config["host"], m)) m.Run() fmt.Println("[ ---------------------------------------------------------->>> ") fmt.Printf("start web server failed, please check if %s is already used.", Config["host"]) fmt.Println(" <<<----------------------------------------------------------] ") }
//HLCross strategy func (HLCross *HLCrossStrategy) Tick(records []Record) bool { //read config tradeAmount := Option["tradeAmount"] stoploss, err := strconv.ParseFloat(Option["stoploss"], 64) if err != nil { logger.Errorln("config item stoploss is not float") return false } var Time []string var Price []float64 var Volumn []float64 for _, v := range records { Time = append(Time, v.TimeStr) Price = append(Price, v.Close) Volumn = append(Volumn, v.Volumn) } length := len(Price) if HLCross.PrevClosePrice != records[length-1].Close || HLCross.PrevHighPrice != records[length-2].High || HLCross.PrevLowPrice != records[length-2].Low { HLCross.PrevClosePrice = records[length-1].Close HLCross.PrevHighPrice = records[length-2].High HLCross.PrevLowPrice = records[length-2].Low logger.Infof("nowClose %0.02f prevHigh %0.02f prevLow %0.02f\n", records[length-1].Close, records[length-2].High, records[length-2].Low) } //HLCross cross if records[length-1].Close > records[length-2].High { if Option["enable_trading"] == "1" && HLCross.PrevHLCrossTrade != "buy" { warning := "HLCross up, 买入buy In<----市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("buy", Price[length-1]) logger.Infoln(warning) if Buy(getTradePrice("buy", Price[length-1]), tradeAmount) != "0" { HLCross.PrevBuyPirce = Price[length-1] warning += "[委托成功]" HLCross.PrevHLCrossTrade = "buy" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } else if records[length-1].Close < records[length-2].Low { if Option["enable_trading"] == "1" && HLCross.PrevHLCrossTrade != "sell" { warning := "HLCross down, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) logger.Infoln(warning) if Sell(getTradePrice("sell", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" HLCross.PrevHLCrossTrade = "sell" HLCross.PrevBuyPirce = 0 } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } //do sell when price is below stoploss point if Price[length-1] < HLCross.PrevBuyPirce*(1-stoploss*0.01) { if Option["enable_trading"] == "1" && HLCross.PrevHLCrossTrade != "sell" { warning := "stop loss, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) logger.Infoln(warning) if Sell(getTradePrice("sell", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" HLCross.PrevHLCrossTrade = "sell" HLCross.PrevBuyPirce = 0 } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } return true }
//xxx strategy func (kdjStrategy *KDJStrategy) Tick(records []Record) bool { //实现自己的策略 tradeAmount := Option["tradeAmount"] var Time []string var Price []float64 var Volumn []float64 for _, v := range records { Time = append(Time, v.TimeStr) Price = append(Price, v.Close) Volumn = append(Volumn, v.Volumn) //Price = append(Price, (v.Close+v.Open+v.High+v.Low)/4.0) //Price = append(Price, v.Low) } length := len(records) if kdjStrategy.PrevTime == records[length-1].TimeStr && kdjStrategy.PrevPrice == records[length-1].Close { return false } //K线为白,D线为黄,J线为红,K in middle k, d, j := getKDJ(records) if kdjStrategy.PrevTime != records[length-1].TimeStr || kdjStrategy.PrevPrice != records[length-1].Close { kdjStrategy.PrevTime = records[length-1].TimeStr kdjStrategy.PrevPrice = records[length-1].Close logger.Infoln(records[length-1].TimeStr, records[length-1].Close) logger.Infof("d(黄线)%0.0f\tk(白线)%0.0f\tj(红线)%0.0f\n", d[length-2], k[length-2], j[length-2]) logger.Infof("d(黄线)%0.0f\tk(白线)%0.0f\tj(红线)%0.0f\n", d[length-1], k[length-1], j[length-1]) } if ((j[length-2] < k[length-2] && k[length-2] < d[length-2]) || kdjStrategy.PrevKDJTrade == "sell") && (j[length-1] > k[length-1] && k[length-1] > d[length-1]) { logger.Infoln("KDJ up cross") if (kdjStrategy.PrevKDJTrade == "init" && d[length-2] <= 30) || kdjStrategy.PrevKDJTrade == "sell" { //do buy warning := "KDJ up cross, 买入buy In<----市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("buy", Price[length-1]) logger.Infoln(warning) if Buy(getTradePrice("buy", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } kdjStrategy.PrevKDJTrade = "buy" go email.TriggerTrender(warning) } } if ((j[length-2] > k[length-2] && k[length-2] > d[length-2]) || kdjStrategy.PrevKDJTrade == "buy") && (j[length-1] < k[length-1] && k[length-1] < d[length-1]) { logger.Infoln("KDJ down cross") if (kdjStrategy.PrevKDJTrade == "init" && d[length-2] >= 70) || kdjStrategy.PrevKDJTrade == "buy" { //do sell warning := "KDJ down cross, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) logger.Infoln(warning) if Sell(getTradePrice("sell", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } kdjStrategy.PrevKDJTrade = "sell" go email.TriggerTrender(warning) } } return true }
//EMA strategy func (emamacdemaStrategy *EMAMACDEMAStrategy) Tick(records []Record) bool { //read config shortEMA, _ := strconv.Atoi(Option["shortEMA"]) longEMA, _ := strconv.Atoi(Option["longEMA"]) signalPeriod, _ := strconv.Atoi(Option["signalPeriod"]) nTradeAmount, err := strconv.ParseFloat(Option["tradeAmount"], 64) if err != nil { logger.Errorln("config item tradeAmount is not float") return false } MacdTradeAmount := fmt.Sprintf("%0.02f", 0.5*nTradeAmount) tradeAmount := Option["tradeAmount"] stoploss, err := strconv.ParseFloat(Option["stoploss"], 64) if err != nil { logger.Errorln("config item stoploss is not float") return false } MACDbuyThreshold, err := strconv.ParseFloat(Option["MACDbuyThreshold"], 64) if err != nil { logger.Errorln("config item MACDbuyThreshold is not float") return false } MACDsellThreshold, err := strconv.ParseFloat(Option["MACDsellThreshold"], 64) if err != nil { logger.Errorln("config item MACDsellThreshold is not float") return false } var Time []string var Price []float64 var Volumn []float64 for _, v := range records { Time = append(Time, v.TimeStr) Price = append(Price, v.Close) Volumn = append(Volumn, v.Volumn) //Price = append(Price, (v.Close+v.Open+v.High+v.Low)/4.0) //Price = append(Price, v.Low) } //compute the indictor emaShort := EMA(Price, shortEMA) emaLong := EMA(Price, longEMA) EMAdif := getMACDdif(emaShort, emaLong) MACDdif := getMACDdif(emaShort, emaLong) MACDSignal := getMACDSignal(MACDdif, signalPeriod) MACDHistogram := getMACDHistogram(MACDdif, MACDSignal) length := len(Price) if emamacdemaStrategy.PrevEMACross == "unknown" { if is_uptrend(EMAdif[length-3]) { emamacdemaStrategy.PrevEMACross = "up" } else if is_downtrend(EMAdif[length-3]) { emamacdemaStrategy.PrevEMACross = "down" } else { emamacdemaStrategy.PrevEMACross = "unknown" } logger.Infoln("prev cross is", emamacdemaStrategy.PrevEMACross) if is_uptrend(EMAdif[length-3]) { logger.Infoln("上一个趋势是上涨,等待卖出点触发") } else if is_downtrend(EMAdif[length-3]) { logger.Infoln("上一个趋势是下跌,等待买入点触发") } else { logger.Infoln("上一个趋势是unknown。。。") } } if EMAdif[length-1] != emamacdemaStrategy.PrevEMAdif { emamacdemaStrategy.PrevEMAdif = EMAdif[length-1] logger.Infof("EMA [%0.02f,%0.02f,%0.02f] Diff:%0.03f\t%0.03f\n", Price[length-1], emaShort[length-1], emaLong[length-1], EMAdif[length-2], EMAdif[length-1]) } if MACDdif[length-1] != emamacdemaStrategy.PrevMACDdif { emamacdemaStrategy.PrevMACDdif = MACDdif[length-1] logger.Infof("MACD:d=%5.03f\ts=%5.03f\th=%5.03f\tpre-h=%5.03f\n", MACDdif[length-1], MACDSignal[length-1], MACDHistogram[length-1], MACDHistogram[length-2]) } //reset LessBuyThreshold LessSellThreshold flag when (^ or V) happen if emamacdemaStrategy.LessBuyThreshold && is_downtrend(EMAdif[length-1]) { emamacdemaStrategy.LessBuyThreshold = false emamacdemaStrategy.PrevEMACross = "down" //reset logger.Infoln("down->up(EMA diff < buy threshold)->down ^") } if emamacdemaStrategy.LessSellThreshold && is_uptrend(EMAdif[length-1]) { emamacdemaStrategy.LessSellThreshold = false emamacdemaStrategy.PrevEMACross = "up" //reset logger.Infoln("up->down(EMA diff > sell threshold)->up V") } //EMA cross if (emamacdemaStrategy.is_upcross(EMAdif[length-2], EMAdif[length-1]) || emamacdemaStrategy.LessBuyThreshold) || (emamacdemaStrategy.is_downcross(EMAdif[length-2], EMAdif[length-1]) || emamacdemaStrategy.LessSellThreshold) { //up cross //do buy when cross up if emamacdemaStrategy.is_upcross(EMAdif[length-2], EMAdif[length-1]) || emamacdemaStrategy.LessBuyThreshold { if Option["enable_trading"] == "1" && emamacdemaStrategy.PrevEMATrade != "buy" { emamacdemaStrategy.PrevEMACross = "up" if emamacdemaStrategy.checkThreshold("buy", EMAdif[length-1]) { emamacdemaStrategy.PrevEMATrade = "buy" diff := fmt.Sprintf("%0.03f", EMAdif[length-1]) warning := "EMA up cross, 买入buy In<----市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("buy", Price[length-1]) + ",diff" + diff logger.Infoln(warning) if buy(getTradePrice("buy", Price[length-1]), tradeAmount) != "0" { emamacdemaStrategy.PrevBuyPirce = Price[length-1] warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } } //do sell when cross down if emamacdemaStrategy.is_downcross(EMAdif[length-2], EMAdif[length-1]) || emamacdemaStrategy.LessSellThreshold { emamacdemaStrategy.PrevEMACross = "down" if Option["enable_trading"] == "1" && emamacdemaStrategy.PrevEMATrade != "sell" { if emamacdemaStrategy.checkThreshold("sell", EMAdif[length-1]) { emamacdemaStrategy.PrevEMATrade = "sell" diff := fmt.Sprintf("%0.03f", EMAdif[length-1]) warning := "EMA down cross, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) + ",diff" + diff logger.Infoln(warning) var ematradeAmount string if emamacdemaStrategy.PrevMACDTrade == "sell" { ematradeAmount = MacdTradeAmount emamacdemaStrategy.PrevMACDTrade = "init" } else { ematradeAmount = tradeAmount } if sell(getTradePrice("sell", Price[length-1]), ematradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } } //backup the kline data for analyze if Config["env"] == "dev" { backup(Time[length-1]) } } //macd cross if MACDdif[length-1] > 0 { if (MACDHistogram[length-2] < -0.000001 && MACDHistogram[length-1] > MACDbuyThreshold) || (emamacdemaStrategy.PrevMACDTrade == "sell" && MACDHistogram[length-2] > 0.000001 && MACDHistogram[length-1] > MACDbuyThreshold) { if Option["enable_trading"] == "1" && emamacdemaStrategy.PrevMACDTrade == "sell" { emamacdemaStrategy.PrevMACDTrade = "buy" histogram := fmt.Sprintf("%0.03f", MACDHistogram[length-1]) warning := "MACD up cross, 买入buy In<----市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("buy", Price[length-1]) + ",histogram" + histogram logger.Infoln(warning) if buy(getTradePrice("buy", Price[length-1]), MacdTradeAmount) != "0" { emamacdemaStrategy.PrevBuyPirce = Price[length-1] warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } else if (Price[length-1] < emaLong[length-1]) && ((MACDHistogram[length-2] > 0.000001 && MACDHistogram[length-1] < MACDsellThreshold) || (emamacdemaStrategy.PrevMACDTrade == "buy" && MACDHistogram[length-2] < -0.000001 && MACDHistogram[length-1] < MACDsellThreshold)) { if Option["enable_trading"] == "1" && emamacdemaStrategy.PrevMACDTrade != "sell" { emamacdemaStrategy.PrevMACDTrade = "sell" histogram := fmt.Sprintf("%0.03f", MACDHistogram[length-1]) warning := "MACD down cross, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) + ",histogram" + histogram logger.Infoln(warning) if sell(getTradePrice("sell", Price[length-1]), MacdTradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } } //do sell when price is below stoploss point if Price[length-1] < emamacdemaStrategy.PrevBuyPirce*(1-stoploss*0.01) { if Option["enable_trading"] == "1" && emamacdemaStrategy.PrevEMATrade != "sell" { warning := "stop loss, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) logger.Infoln(warning) var ematradeAmount string if emamacdemaStrategy.PrevMACDTrade == "sell" { ematradeAmount = MacdTradeAmount } else { ematradeAmount = tradeAmount } if sell(getTradePrice("sell", Price[length-1]), ematradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) emamacdemaStrategy.PrevEMATrade = "sell" emamacdemaStrategy.PrevMACDTrade = "init" emamacdemaStrategy.PrevBuyPirce = 0 } } return true }
func SendEmail(warning string) { if !GetBacktest() { go email.TriggerTrender(warning) } }
//MACD strategy func (macdStrategy *MACDStrategy) Tick(records []Record) bool { //read config shortEMA, _ := strconv.Atoi(Option["shortEMA"]) longEMA, _ := strconv.Atoi(Option["longEMA"]) signalPeriod, _ := strconv.Atoi(Option["signalPeriod"]) /* MACDMinThreshold, err := strconv.ParseFloat(Option["MACDMinThreshold"], 64) if err != nil { logger.Debugln("config item MACDMinThreshold is not float") return false } */ tradeAmount := Option["tradeAmount"] stoploss, err := strconv.ParseFloat(Option["stoploss"], 64) if err != nil { logger.Errorln("config item stoploss is not float") return false } MACDbuyThreshold, err := strconv.ParseFloat(Option["MACDbuyThreshold"], 64) if err != nil { logger.Errorln("config item MACDbuyThreshold is not float") return false } MACDsellThreshold, err := strconv.ParseFloat(Option["MACDsellThreshold"], 64) if err != nil { logger.Errorln("config item MACDsellThreshold is not float") return false } var Time []string var Price []float64 var Volumn []float64 for _, v := range records { Time = append(Time, v.TimeStr) Price = append(Price, v.Close) Volumn = append(Volumn, v.Volumn) //Price = append(Price, (v.Close+v.Open+v.High+v.Low)/4.0) //Price = append(Price, v.Low) } //compute the indictor emaShort := EMA(Price, shortEMA) emaLong := EMA(Price, longEMA) MACDdif := getMACDdif(emaShort, emaLong) MACDSignal := getMACDSignal(MACDdif, signalPeriod) MACDHistogram := getMACDHistogram(MACDdif, MACDSignal) length := len(Price) if MACDdif[length-1] != macdStrategy.PrevMACDdif { macdStrategy.PrevMACDdif = MACDdif[length-1] logger.Infof("MACD:d%5.03f\ts%5.03f\tph%5.03f\th%5.03f\tPrice:%5.02f\n", MACDdif[length-1], MACDSignal[length-1], MACDHistogram[length-2], MACDHistogram[length-1], Price[length-1]) } //macd cross if (MACDHistogram[length-2] < -0.000001 && MACDHistogram[length-1] > MACDbuyThreshold) || (macdStrategy.PrevMACDTrade == "sell" && MACDHistogram[length-2] > 0.000001 && MACDHistogram[length-1] > MACDbuyThreshold) { if Option["enable_trading"] == "1" && macdStrategy.PrevMACDTrade != "buy" { macdStrategy.PrevMACDTrade = "buy" histogram := fmt.Sprintf("%0.03f", MACDHistogram[length-1]) warning := "MACD up cross, 买入buy In<----市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("buy", Price[length-1]) + ",histogram" + histogram logger.Infoln(warning) if Buy(getTradePrice("buy", Price[length-1]), tradeAmount) != "0" { macdStrategy.PrevBuyPirce = Price[length-1] warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } else if (MACDHistogram[length-2] > 0.000001 && MACDHistogram[length-1] < MACDsellThreshold) || (macdStrategy.PrevMACDTrade == "buy" && MACDHistogram[length-2] < -0.000001 && MACDHistogram[length-1] < MACDsellThreshold) { if Option["enable_trading"] == "1" && macdStrategy.PrevMACDTrade != "sell" { macdStrategy.PrevMACDTrade = "sell" histogram := fmt.Sprintf("%0.03f", MACDHistogram[length-1]) warning := "MACD down cross, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) + ",histogram" + histogram logger.Infoln(warning) if Sell(getTradePrice("sell", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } //do sell when price is below stoploss point if Price[length-1] < macdStrategy.PrevBuyPirce*(1-stoploss*0.01) { if Option["enable_trading"] == "1" && macdStrategy.PrevMACDTrade != "sell" { warning := "stop loss, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) logger.Infoln(warning) if Sell(getTradePrice("sell", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) macdStrategy.PrevMACDTrade = "sell" macdStrategy.PrevBuyPirce = 0 } } return true }
//MACD strategy func (macdStrategy *MACDStrategy) Perform(tradeAPI TradeAPI, Time []string, Price []float64, Volumn []float64) bool { //read config shortEMA, _ := strconv.Atoi(Option["shortEMA"]) longEMA, _ := strconv.Atoi(Option["longEMA"]) signalPeriod, _ := strconv.Atoi(Option["signalPeriod"]) /* MACDMinThreshold, err := strconv.ParseFloat(Option["MACDMinThreshold"], 64) if err != nil { logger.Debugln("config item MACDMinThreshold is not float") return false } */ tradeAmount := Option["tradeAmount"] stoploss, err := strconv.ParseFloat(Option["stoploss"], 64) if err != nil { logger.Errorln("config item stoploss is not float") return false } MACDbuyThreshold, err := strconv.ParseFloat(Option["MACDbuyThreshold"], 64) if err != nil { logger.Errorln("config item MACDbuyThreshold is not float") return false } MACDsellThreshold, err := strconv.ParseFloat(Option["MACDsellThreshold"], 64) if err != nil { logger.Errorln("config item MACDsellThreshold is not float") return false } //compute the indictor emaShort := EMA(Price, shortEMA) emaLong := EMA(Price, longEMA) MACDdif := getMACDdif(emaShort, emaLong) MACDSignal := getMACDSignal(MACDdif, signalPeriod) MACDHistogram := getMACDHistogram(MACDdif, MACDSignal) length := len(Price) if MACDdif[length-1] != macdStrategy.PrevMACDdif { macdStrategy.PrevMACDdif = MACDdif[length-1] logger.Infof("MACD:d%5.03f\ts%5.03f\th%5.03f\tPrice:%5.02f\n", MACDdif[length-1], MACDSignal[length-1], MACDHistogram[length-1], Price[length-1]) } //macd cross if (MACDHistogram[length-2] < -0.000001 && MACDHistogram[length-1] > MACDbuyThreshold) || (macdStrategy.PrevMACDTrade == "sell" && MACDHistogram[length-2] > 0.000001 && MACDHistogram[length-1] > MACDbuyThreshold) { if Option["disable_trading"] != "1" && macdStrategy.PrevMACDTrade != "buy" { macdStrategy.PrevMACDTrade = "buy" histogram := fmt.Sprintf("%0.03f", MACDHistogram[length-1]) warning := "MACD up cross, 买入buy In<----市价" + tradeAPI.GetTradePrice("") + ",委托价" + tradeAPI.GetTradePrice("buy") + ",histogram" + histogram logger.Infoln(warning) if tradeAPI.Buy(tradeAPI.GetTradePrice("buy"), tradeAmount) { macdStrategy.PrevBuyPirce = Price[length-1] warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } else if (MACDHistogram[length-2] > 0.000001 && MACDHistogram[length-1] < MACDsellThreshold) || (macdStrategy.PrevMACDTrade == "buy" && MACDHistogram[length-2] < -0.000001 && MACDHistogram[length-1] < MACDsellThreshold) { if Option["disable_trading"] != "1" && macdStrategy.PrevMACDTrade != "sell" { macdStrategy.PrevMACDTrade = "sell" histogram := fmt.Sprintf("%0.03f", MACDHistogram[length-1]) warning := "MACD down cross, 卖出Sell Out---->市价" + tradeAPI.GetTradePrice("") + ",委托价" + tradeAPI.GetTradePrice("sell") + ",histogram" + histogram logger.Infoln(warning) if tradeAPI.Sell(tradeAPI.GetTradePrice("sell"), tradeAmount) { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } //do sell when price is below stoploss point if Price[length-1] < macdStrategy.PrevBuyPirce*(1-stoploss*0.01) { if Option["disable_trading"] != "1" && macdStrategy.PrevMACDTrade != "sell" { macdStrategy.PrevMACDTrade = "sell" macdStrategy.PrevBuyPirce = 0 warning := "stop loss, 卖出Sell Out---->市价" + tradeAPI.GetTradePrice("") + ",委托价" + tradeAPI.GetTradePrice("sell") logger.Infoln(warning) if tradeAPI.Sell(tradeAPI.GetTradePrice("sell"), tradeAmount) { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } return true }
//KDJ-EX strategy func (kdjex *KDJexStrategy) Tick(records []Record) bool { const btcslap = 0.2 const ltcslap = 0.01 const timeout = 300 //s const ordercount = 5 tradeAmount := Option["tradeAmount"] numTradeAmount, err := strconv.ParseFloat(Option["tradeAmount"], 64) if err != nil { logger.Errorln("config item tradeAmount is not float") return false } var slappage float64 symbol := Option["symbol"] if symbol == "btc_cny" { slappage = btcslap } else { slappage = ltcslap } nSplitTradeAmount := numTradeAmount / float64(ordercount) splitTradeAmount := fmt.Sprintf("%f", nSplitTradeAmount) stoploss, err := strconv.ParseFloat(Option["stoploss"], 64) if err != nil { logger.Errorln("config item stoploss is not float") return false } var Time []string var Price []float64 var Volumn []float64 for _, v := range records { Time = append(Time, v.TimeStr) Price = append(Price, v.Close) Volumn = append(Volumn, v.Volumn) } length := len(records) if kdjex.PrevTime == records[length-1].TimeStr && kdjex.PrevPrice == records[length-1].Close { return false } //K线为白,D线为黄,J线为红,K in middle k, d, j := getKDJ(records) if kdjex.PrevTime != records[length-1].TimeStr || kdjex.PrevPrice != records[length-1].Close { kdjex.PrevTime = records[length-1].TimeStr kdjex.PrevPrice = records[length-1].Close logger.Infoln(records[length-1].TimeStr, records[length-1].Close) logger.Infof("d(黄线)%0.0f\tk(白线)%0.0f\tj(红线)%0.0f\n", d[length-2], k[length-2], j[length-2]) logger.Infof("d(黄线)%0.0f\tk(白线)%0.0f\tj(红线)%0.0f\n", d[length-1], k[length-1], j[length-1]) if j[length-1] > k[length-1] { logger.Infoln("KDJ up trend") } else { logger.Infoln("KDJ down trend") } } if (j[length-2] < k[length-2] && k[length-2] < d[length-2]) && (j[length-1] > k[length-1] && k[length-1] > d[length-1]) { logger.Infoln("----------------->KDJ up cross", kdjex.PrevKDJTrade, d[length-2]) if kdjex.PrevKDJTrade != "buy" && j[length-2] <= 20 { //do buy ret, orderbook := GetOrderBook() if !ret { logger.Infoln("get orderbook failed 1") ret, orderbook = GetOrderBook() //try again if !ret { logger.Infoln("get orderbook failed 2") return false } } logger.Infoln("卖一", (orderbook.Asks[len(orderbook.Asks)-1])) logger.Infoln("买一", orderbook.Bids[0]) logger.Infoln("X 两根K线最低价", records[length-2].Low, records[length-1].Low) logger.Infoln("X 两根K线最高价", records[length-2].High, records[length-1].High) avgLow := (records[length-2].Close + records[length-1].Low) / 2.0 logger.Infoln("X 两根K线的最低平均价", avgLow) //fmt.Println(ret, orderbook) warning := "KDJ up cross, 买入buy In<----限价单" for i := 1; i <= ordercount; i++ { warning := "KDJ up cross, 买入buy In<----限价单" tradePrice := fmt.Sprintf("%f", avgLow+slappage*float64(i)) buyID := buy(tradePrice, splitTradeAmount) if buyID != "0" { warning += "[委托成功]" kdjex.BuyId = append(kdjex.BuyId, buyID) } else { warning += "[委托失败]" } logger.Infoln(warning) } kdjex.BuyBegin = time.Now() kdjex.PrevKDJTrade = "buy" kdjex.PrevBuyPirce = avgLow logger.Infoln("------------>>>stoploss price", kdjex.PrevBuyPirce*(1-stoploss*0.01)) _, ret = GetAccount() if !ret { logger.Infoln("GetAccount failed") } go email.TriggerTrender(warning) } } if (j[length-2] > k[length-2] && k[length-2] > d[length-2]) && (j[length-1] < k[length-1] && k[length-1] < d[length-1]) { logger.Infoln("<----------------------KDJ down cross", kdjex.PrevKDJTrade, d[length-2]) if kdjex.PrevKDJTrade != "sell" && j[length-2] >= 80 { //do sell ret, orderbook := GetOrderBook() if !ret { logger.Infoln("get orderbook failed 1") ret, orderbook = GetOrderBook() //try again if !ret { logger.Infoln("get orderbook failed 2") return false } } logger.Infoln("卖一", (orderbook.Asks[len(orderbook.Asks)-1])) logger.Infoln("买一", orderbook.Bids[0]) logger.Infoln("X 两根K线最低价", records[length-2].Low, records[length-1].Low) logger.Infoln("X 两根K线最高价", records[length-2].High, records[length-1].High) avgHigh := (records[length-2].Close + records[length-1].High) / 2.0 logger.Infoln("X 两根K线的最高平均价", avgHigh) warning := "KDJ down cross, 卖出Sell Out---->限价单" for i := 1; i <= ordercount; i++ { warning := "KDJ down cross, 卖出Sell Out---->限价单" tradePrice := fmt.Sprintf("%f", avgHigh-slappage*float64(i)) sellID := sell(tradePrice, splitTradeAmount) if sellID != "0" { warning += "[委托成功]" kdjex.SellId = append(kdjex.SellId, sellID) } else { warning += "[委托失败]" } logger.Infoln(warning) } kdjex.SellBegin = time.Now() kdjex.PrevKDJTrade = "sell" _, ret = GetAccount() if !ret { logger.Infoln("GetAccount failed") } go email.TriggerTrender(warning) } } //do sell when price is below stoploss point if Price[length-1] < kdjex.PrevBuyPirce*(1-stoploss*0.01) { if Option["disable_trading"] != "1" && kdjex.PrevKDJTrade != "sell" { kdjex.PrevKDJTrade = "sell" kdjex.PrevBuyPirce = 0 warning := "!<------------------stop loss, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("sell", Price[length-1]) logger.Infoln(warning) if sell(getTradePrice("sell", Price[length-1]), tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" for i := 1; i <= ordercount; i++ { warning := "stop loss, 卖出Sell Out---->限价单" sellID := sell(getTradePrice("sell", Price[length-1]), splitTradeAmount) if sellID != "0" { warning += "[委托成功]" kdjex.SellId = append(kdjex.SellId, sellID) } else { warning += "[委托失败]" } logger.Infoln(warning) } } kdjex.SellBegin = time.Now() kdjex.PrevKDJTrade = "sell" _, ret := GetAccount() if !ret { logger.Infoln("GetAccount failed") } go email.TriggerTrender(warning) } } //check timeout trade now := time.Now() logger.Infoln("time go ", int64(now.Sub(kdjex.BuyBegin)/time.Second)) logger.Infoln("BuyId len", len(kdjex.BuyId), cap(kdjex.BuyId)) logger.Infoln("SellId len", len(kdjex.SellId), cap(kdjex.SellId)) if len(kdjex.BuyId) != 0 && int64(now.Sub(kdjex.BuyBegin)/time.Second) > timeout { //todo- for _, BuyId := range kdjex.BuyId { warning := "<--------------buy order timeout, cancel-------------->" + BuyId if CancelOrder(BuyId) { warning += "[Cancel委托成功]" } else { warning += "[Cancel委托失败]" } logger.Infoln(warning) time.Sleep(1 * time.Second) time.Sleep(500 * time.Microsecond) } kdjex.BuyId = kdjex.BuyId[:0] } if len(kdjex.SellId) != 0 && int64(now.Sub(kdjex.SellBegin)/time.Second) > timeout { //todo for _, SellId := range kdjex.SellId { warning := "<--------------sell order timeout, cancel------------->" + SellId if CancelOrder(SellId) { warning += "[Cancel委托成功]" } else { warning += "[Cancel委托失败]" } logger.Infoln(warning) time.Sleep(1 * time.Second) time.Sleep(500 * time.Microsecond) } kdjex.SellId = kdjex.SellId[:0] } return true }
//EMA strategy func (emaStrategy *EMAStrategy) Tick(records []Record) bool { //read config shortEMA, _ := strconv.Atoi(Option["shortEMA"]) longEMA, _ := strconv.Atoi(Option["longEMA"]) _, err := strconv.ParseFloat(Option["tradeAmount"], 64) if err != nil { logger.Errorln("config item tradeAmount is not float") return false } tradeAmount := Option["tradeAmount"] stoploss, err := strconv.ParseFloat(Option["stoploss"], 64) if err != nil { logger.Errorln("config item stoploss is not float") return false } var Time []string var Price []float64 var Volumn []float64 for _, v := range records { Time = append(Time, v.TimeStr) Price = append(Price, v.Close) Volumn = append(Volumn, v.Volumn) //Price = append(Price, (v.Close+v.Open+v.High+v.Low)/4.0) //Price = append(Price, v.Low) } //compute the indictor emaShort := EMA(Price, shortEMA) emaLong := EMA(Price, longEMA) EMAdif := getMACDdif(emaShort, emaLong) length := len(Price) if emaStrategy.PrevEMACross == "unknown" { if is_uptrend(EMAdif[length-3]) { emaStrategy.PrevEMACross = "up" } else if is_downtrend(EMAdif[length-3]) { emaStrategy.PrevEMACross = "down" } else { emaStrategy.PrevEMACross = "unknown" } logger.Infoln("prev cross is", emaStrategy.PrevEMACross) if is_uptrend(EMAdif[length-3]) { logger.Infoln("上一个趋势是上涨,等待卖出点触发") } else if is_downtrend(EMAdif[length-3]) { logger.Infoln("上一个趋势是下跌,等待买入点触发") } else { logger.Infoln("上一个趋势是unknown。。。") } } //go TriggerPrice(Price[length-1]) if EMAdif[length-1] != emaStrategy.PrevEMAdif { emaStrategy.PrevEMAdif = EMAdif[length-1] logger.Infof("EMA [%0.02f,%0.02f,%0.02f] Diff:%0.03f\t%0.03f\n", Price[length-1], emaShort[length-1], emaLong[length-1], EMAdif[length-2], EMAdif[length-1]) } //reset LessBuyThreshold LessSellThreshold flag when (^ or V) happen if emaStrategy.LessBuyThreshold && is_downtrend(EMAdif[length-1]) { emaStrategy.LessBuyThreshold = false emaStrategy.PrevEMACross = "down" //reset logger.Infoln("down->up(EMA diff < buy threshold)->down ^") } if emaStrategy.LessSellThreshold && is_uptrend(EMAdif[length-1]) { emaStrategy.LessSellThreshold = false emaStrategy.PrevEMACross = "up" //reset logger.Infoln("up->down(EMA diff > sell threshold)->up V") } //EMA cross if (emaStrategy.is_upcross(EMAdif[length-2], EMAdif[length-1]) || emaStrategy.LessBuyThreshold) || (emaStrategy.is_downcross(EMAdif[length-2], EMAdif[length-1]) || emaStrategy.LessSellThreshold) { //up cross //do buy when cross up if emaStrategy.is_upcross(EMAdif[length-2], EMAdif[length-1]) || emaStrategy.LessBuyThreshold { if Option["enable_trading"] == "1" && emaStrategy.PrevEMATrade != "buy" { emaStrategy.PrevEMACross = "up" if emaStrategy.checkThreshold("buy", EMAdif[length-1]) { emaStrategy.PrevEMATrade = "buy" diff := fmt.Sprintf("%0.03f", EMAdif[length-1]) warning := "EMA up cross, 买入buy In<----市价" + getTradePrice("", Price[length-1]) + ",委托价" + getTradePrice("buy", Price[length-1]) + ",diff" + diff logger.Infoln(warning) if Buy(getTradePrice("buy", Price[length-1]), tradeAmount) != "0" { emaStrategy.PrevBuyPirce = Price[length-1] warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } } //do sell when cross down if emaStrategy.is_downcross(EMAdif[length-2], EMAdif[length-1]) || emaStrategy.LessSellThreshold { emaStrategy.PrevEMACross = "down" if Option["enable_trading"] == "1" && emaStrategy.PrevEMATrade != "sell" { if emaStrategy.checkThreshold("sell", EMAdif[length-1]) { emaStrategy.PrevEMATrade = "sell" var tradePrice string if Option["discipleMode"] == "1" { stoplossPrice := emaStrategy.PrevBuyPirce * (1 - stoploss*0.01) if Price[length-1] > stoplossPrice { tradePrice = getTradePrice("sell", Price[length-1]) } else { discipleValue, err := strconv.ParseFloat(Option["discipleValue"], 64) if err != nil { logger.Errorln("config item discipleValue is not float") return false } tradePrice = fmt.Sprintf("%f", emaStrategy.PrevBuyPirce+discipleValue) } } else { tradePrice = getTradePrice("sell", Price[length-1]) } diff := fmt.Sprintf("%0.03f", EMAdif[length-1]) warning := "EMA down cross, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + tradePrice + ",diff" + diff logger.Infoln(warning) if Sell(tradePrice, tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } go email.TriggerTrender(warning) } } } //backup the kline data for analyze if Config["env"] == "dev" { backup(Time[length-1]) } } //do sell when price is below stoploss point stoplossPrice := emaStrategy.PrevBuyPirce * (1 - stoploss*0.01) if Price[length-1] <= stoplossPrice { if Option["enable_trading"] == "1" && emaStrategy.PrevEMATrade != "sell" { emaStrategy.PrevEMATrade = "sell" var tradePrice string if Option["discipleMode"] == "1" { if Price[length-1] > stoplossPrice { tradePrice = getTradePrice("sell", Price[length-1]) } else { discipleValue, err := strconv.ParseFloat(Option["discipleValue"], 64) if err != nil { logger.Errorln("config item discipleValue is not float") return false } tradePrice = fmt.Sprintf("%f", emaStrategy.PrevBuyPirce+discipleValue) } } else { tradePrice = getTradePrice("sell", Price[length-1]) } warning := "stop loss, 卖出Sell Out---->市价" + getTradePrice("", Price[length-1]) + ",委托价" + tradePrice logger.Infoln(warning) if Sell(tradePrice, tradeAmount) != "0" { warning += "[委托成功]" } else { warning += "[委托失败]" } emaStrategy.PrevBuyPirce = 0 go email.TriggerTrender(warning) } } return true }
func Buy() string { if PrevTrade == "buy" { return "0" } // init isStoploss = false // compute the price price, nPrice, warning := getBuyPrice() // compute the amount amount := Option["tradeAmount"] nAmount, err := strconv.ParseFloat(amount, 64) if err != nil { logger.Infoln("amount is not float") return "0" } Available_cny := GetAvailable_cny() if Available_cny < nPrice*nAmount { var nMinTradeAmount float64 nAmount = Available_cny / nPrice symbol := Option["symbol"] if symbol == "btc_cny" { nMinTradeAmount = 0.1 } else { nMinTradeAmount = 0.01 } if nAmount < nMinTradeAmount { warning += "没有足够的法币余额" logger.Infoln(warning) PrevTrade = "buy" PrevBuyPirce = nPrice return "0" } amount = fmt.Sprintf("%02f", nAmount) } warning += "---->数量" + amount buyID := buy(price, amount) if buyID == "-1" { warning += " [模拟]" } else if buyID == "0" { warning += "[委托失败]" } else { warning += "[委托成功]" + buyID } logger.Infoln(warning) var coin string if Option["symbol"] == "btc_cny" { coin = "比特币" } else { coin = "莱特币" } if buyID != "0" { if !GetBacktest() { logger.Tradef("在%s,根据策略%s周期%s,以价格%s买入%s个%s\n", Option["tradecenter"], Option["strategy"], Option["tick_interval"], price, amount, coin) go email.TriggerTrender(warning) } else { t := time.Unix(GetBtTime(), 0) logger.Backtestf("%s 在simulate,根据策略%s周期%s,以价格%s买入%s个%s\n", t.Format("2006-01-02 15:04:05"), Option["strategy"], Option["tick_interval"], price, amount, coin) } } return buyID }