// Copyright 2013-2014 Fuzamei tech Ltd. All rights reserved. package tick // 本文件实现easyforex数据源的tick数据获取下载和保存 import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "strconv" "strings" "time" "tickserver/markinfo" "tickserver/server/market" "github.com/ble/cookiejar" ) var pair = []string{ "EURUSD", "EURGBP", "GBPUSD", "USDJPY", "USDCHF", "AUDUSD", "USDCAD", "NZDUSD", "CHFJPY", "EURJPY", "EURCHF", "EURAUD", "EURCAD", "GBPCHF", "GBPJPY", "CADJPY", "AUDJPY", "AUDCAD", "AUDNZD", "XAGUSD", "XAUUSD", "OILUSD", } var easyforex_base = int(100) func logOn(client *http.Client, username, password string) error { loginUrl := "https://secure.easy-forex.com/ntp/myaccount/services/loginservice.ashx?action=AuthenticateUser" loginUrl = loginUrl + "&username=%s&password=%s&pid=42&culture=Int-en&simulator=false" login := fmt.Sprintf(loginUrl, username, password) resp, err := client.Get(login) if err != nil { return err } defer resp.Body.Close() dec := json.NewDecoder(resp.Body) data := make(map[string]interface{}) err = dec.Decode(&data) if err != nil { return err } if data["encData"] == nil { return fmt.Errorf("error login format.") } doLoginUrl := "https://secure.easy-forex.com/ntp/myaccount/services/loginservice.ashx?action=DoLogin&pid=42&encData=%s&culture=Int-en&isSimulator=&service=0" doLogin := fmt.Sprintf(doLoginUrl, data["encData"].(string)) resp2, err := client.Get(doLogin) if err != nil { return err } defer resp2.Body.Close() dec = json.NewDecoder(resp2.Body) data2 := make(map[string]interface{}) err = dec.Decode(&data2) if err != nil { return err } return nil } type PairStatistics struct { Date time.Time BuyPercent float64 Rates float64 Symbol string } func getStatistics(client *http.Client, symbol string) (stat *PairStatistics, err error) { defer func() { if err2 := recover(); err2 != nil { err = fmt.Errorf("%v", err2) } }() r := []rune(symbol) s1 := string(r[:3]) s2 := string(r[3:]) url := "https://secure.easy-forex.com/ntp/Machine/TradingZone/tz.ashx?RQ=[{%22action%22%3A%22GetCurrencyPairStatistics%22%2C%22args%22%3A" url += "{%22buy%22%3A%22" + s1 + "%22%2C%22sell%22%3A%22" + s2 + "%22}}" url += "%2C{%22action%22%3A%22GetTableMids%22%2C%22args%22%3A{%22isExpanded%22%3A0%2C%22productId%22%3A3}}" url += "%2C{%22action%22%3A%22GetDtrProposal%22%2C%22args%22%3A[null%2C%22USD%22%2C%22AUD%22%2C4%2C100%2C3]}" url += "%2C{%22action%22%3A%22GetFreeBalance%22}]&MODE=isCurrencies&Heartbeat=0" resp, err := client.Get(url) if err != nil { return nil, err } defer resp.Body.Close() buf := bytes.NewBufferString("") _, err = io.Copy(buf, resp.Body) if err != nil { return nil, err } var data []map[string]interface{} s := buf.String() s = strings.Replace(s, "GetCurrencyPairStatistics", `"GetCurrencyPairStatistics"`, 1) s = strings.Replace(s, "GetTableMids", `"GetTableMids"`, 1) s = strings.Replace(s, "GetDtrProposal", `"GetDtrProposal"`, 1) s = strings.Replace(s, "GetFreeBalance", `"GetFreeBalance"`, 1) err = json.Unmarshal([]byte(s), &data) if err != nil { return nil, err } pstat := data[0]["GetCurrencyPairStatistics"].(map[string]interface{}) if _, ok := pstat["error"]; ok { // log.Println("GetCurrencyPairStatistics code = ", pstat["error"], symbol) return nil, nil } currentRate := pstat["currentRate"].(string) buyPercent := pstat["BuyPercent"].(float64) curRateDate := data[0]["GetDtrProposal"].([]interface{})[3].(map[string]interface{})["curRateDate"].(string) gotime, err := parseTime(curRateDate) if err != nil { return nil, err } _, err = markinfo.SymbolId(symbol) if err != nil { return nil, err } stat = &PairStatistics{} stat.Date = gotime stat.BuyPercent = buyPercent stat.Rates, err = strconv.ParseFloat(currentRate, 64) if err != nil { return nil, err } stat.Symbol = symbol return stat, err } func parseTime(curRateDate string) (time.Time, error) { //curRateDate to time //23/01/13 10:48:25.140 curRateDate = strings.Replace(curRateDate, "/", " ", -1) curRateDate = strings.Replace(curRateDate, ":", " ", -1) curRateDate = strings.Replace(curRateDate, ".", " ", -1) parts := strings.Split(curRateDate, " ") dates := make([]int, len(parts)) for i := 0; i < len(dates); i++ { value, err := strconv.Atoi(parts[i]) if err != nil { return time.Time{}, err } dates[i] = value } godate := time.Date(2000+dates[2], time.Month(dates[1]), dates[0], dates[3], dates[4], dates[5], dates[6]*int(time.Millisecond), time.UTC) return godate, nil } // EasyForexDS 实现数据源dataSource接口的定义 type EasyForexDS struct { *DSBase conf *DsConf //insMap map[string]*market.Instrument } func init() { drivers[EasyForex] = newEasyForexDS } func newEasyForexDS(conf *DsConf) (DataSource, error) { eds := &EasyForexDS{ DSBase: NewDsBase(conf), conf: conf, //insMap: edsInsMap(), } eds.insMap = edsInsMap() return eds, nil } func (eds *EasyForexDS) onMarket(ps *PairStatistics) { //insId := market.EasyForexPrefix + ps.Symbol insId, _ := markinfo.SymbolId(ps.Symbol) _, ok := eds.insMap[int64(insId)] if !ok { log.Fatal("EasyForexDS.onMarket error: insId is NOT in insMap:", insId) } //mk := ins.GetMk() mk := &Market{} mk.InsId = int64(insId) mk.Type = IntEasyForex mk.Timestamp = ps.Date.Unix() * 1000 mk.LastPrice = 100 - ps.BuyPercent mk.LastVolume = 1 //ins.SetMk(mk) eds.Save(mk) } /*func (eds *EasyForexDS) runHour() { ht := time.Tick(time.Hour) for _ = range ht { for _, ins := range eds.insMap { eds.Save(ins.GetMk()) } } }*/ func (eds *EasyForexDS) Name() string { return EasyForex } func (eds *EasyForexDS) Run() { log.Println("EasyForexDS.run") //for _, ins := range eds.insMap { //eds.insPublisher.Publish(ins) //} // go eds.runHour() //go eds.RunSave(4) ch := make(chan *PairStatistics, 1024) go func() { for { ps := <-ch eds.onMarket(ps) } }() for { client := &http.Client{Jar: cookiejar.NewJar(false)} err := logOn(client, "Ty2388", "4536888") var stat *PairStatistics var laststat = make(map[string]*PairStatistics) if err != nil { log.Println(err) goto END } for { for i := 0; i < len(pair); i++ { stat, err = getStatistics(client, pair[i]) if err != nil { goto END } if stat != nil { if _, ok := laststat[stat.Symbol]; !ok { ch <- stat laststat[stat.Symbol] = stat } else if *laststat[stat.Symbol] != *stat && laststat[stat.Symbol].Date.Sub(stat.Date) < 0 { ch <- stat laststat[stat.Symbol] = stat } } } } END: log.Println(err) time.Sleep(time.Second) } } //func (eds *EasyForexDS) SubIns() *event.Event { //return eds.insPublisher.Event() //} func edsInsMap() map[int64]*Instrument { insMap := make(map[int64]*Instrument) for _, x := range pair { //id := market.EasyForexPrefix + x id, _ := markinfo.SymbolId(x) u, _ := markinfo.SymbolUint(x) ins := &Instrument{ Id: int64(id), Name: x, ExId: market.EasyForex, Type: market.Forex, PriceInc: u, StartTime: time.Now().Unix() * 1000, } insMap[int64(id)] = ins } return insMap }