func DecimalToString(res decimal.Decimal, min int32, max int32) string { if res.Cmp(decimal.New(10, min)) <= 0 || res.Cmp(decimal.New(10, max)) >= 0 { f, _ := res.Float64() return strconv.FormatFloat(f, 'G', -1, 64) } return res.String() }
func (ex *CaVirtex) PlaceOrder(mode OrderMode, amount decimal.Decimal, price decimal.Decimal, base, counter string) (status, id string, err error) { textMode := "sell" if mode == ORDER_BUY { textMode = "buy" } resp, err := ex.AuthenticatedPost("order", map[string]string{ "currencypair": fmt.Sprintf("%s%s", base, counter), "mode": textMode, "amount": amount.String(), "price": price.String(), }) if err != nil { return "", "", err } result := struct { Status string Message string ApiRate int Order struct { Status string ID int } }{} cnt, err := ioutil.ReadAll(resp.Body) if err != nil { return "", "", err } err = json.Unmarshal(cnt, &result) if err != nil { return "", "", err } if result.Status != "ok" { return "", "", fmt.Errorf("status=%s: %s", result.Status, result.Message) } return result.Order.Status, fmt.Sprintf("%d", result.Order.ID), nil }
func handleConnection(conn net.Conn) { var found bool var QuoteItem QuoteCacheItem if err != nil { // do stuff return } status := make([]byte, 100) _, err = conn.Read(status) if err != nil { // do stuff println("ERROR READ: " + err.Error()) return } status = bytes.Trim(status, "\x00") inputs := strings.Split(string(status), ",") var price decimal.Decimal _, err := strconv.ParseBool(strings.ToLower(inputs[0])) APIUserId := inputs[1] stockSymbol := inputs[2] TransId := "1" GGuid := getNewGuid() Guid := GGuid.String() if len(inputs) > 3 { TransId = inputs[3] Guid = inputs[4] } QuoteItem, found = memCache[stockSymbol] if found { if QuoteItem.Expiration.After(time.Now()) { fmt.Fprintf(conn, string(QuoteItem.Value)+","+QuoteItem.Expiration.String()) conn.Close() hit = hit + 1 return } else { found = false } } miss = miss + 1 if !found { messages := make(chan string) var returned bool = false num_threads := 0 go func() { for returned == false { num_threads = num_threads + 1 go func() { sendString := stockSymbol + "," + APIUserId + "\n" addr, err := net.ResolveTCPAddr("tcp", "quoteserve.seng.uvic.ca:"+quotePort) if err != nil { return } qconn, err := net.DialTCP("tcp", nil, addr) if err != nil { //error println("ERROR qconn: " + err.Error()) return } defer qconn.Close() _, err = fmt.Fprintf(qconn, sendString) if err != nil { failOnError(err, "Error with fprintf") } response := make([]byte, 100) _, err = qconn.Read(response) returned = true messages <- string(response) }() time.Sleep(time.Duration(thread_wait) * time.Millisecond) } }() QuoteReturn := <-messages ParsedQuoteReturn := strings.Split(QuoteReturn, ",") price, err = decimal.NewFromString(ParsedQuoteReturn[0]) if err != nil { //error println("ERROR PARSING") } backoff := 50 + rand.Intn(5) QuoteExpiration := time.Now().Add(time.Duration(backoff) * time.Second) _, err = conn.Write([]byte(price.String() + "," + QuoteExpiration.String())) conn.Close() stockSymbol = ParsedQuoteReturn[1] ReturnUserId := ParsedQuoteReturn[2] msTimeStamp, err := msToTime(ParsedQuoteReturn[3]) if err != nil { //error } cryptoKey := stripCtlAndExtFromUTF8(ParsedQuoteReturn[4]) cryptoKey = strings.TrimSpace(cryptoKey) if ReturnUserId != APIUserId { // system error } QuoteEvent := QuoteServerEvent{ EventType: "QuoteServerEvent", Guid: Guid, OccuredAt: time.Now(), TransactionId: TransId, UserId: APIUserId, Service: "QUOTE", Server: "QuoteCache", Price: price.String(), StockSymbol: stockSymbol, QuoteServerTime: msTimeStamp, Cryptokey: cryptoKey, } SendRabbitMessage(QuoteEvent, QuoteEvent.EventType) tmpQuoteItem := QuoteCacheItem{ Expiration: QuoteExpiration, Value: price.String(), } memCache[stockSymbol] = tmpQuoteItem if err != nil { // system error } for i := 0; i < num_threads-1; i++ { <-messages } close(messages) return } }
func Buy(w http.ResponseWriter, r *http.Request) { zero, _ := decimal.NewFromString("0") type buy_struct struct { Amount string Symbol string } type return_struct struct { Error bool SaleId int Price string NumShares int64 Expiration time.Duration } vars := mux.Vars(r) UserId := vars["id"] TransId := r.Header.Get("X-TransNo") if TransId == "" { TransId = "0" } decoder := json.NewDecoder(r.Body) var t buy_struct err := decoder.Decode(&t) //Audit UserCommand Guid := getNewGuid() CommandEvent := UserCommandEvent{ EventType: "UserCommandEvent", Guid: Guid.String(), OccuredAt: time.Now(), TransactionId: TransId, UserId: UserId, Service: "Command", Server: Hostname, Command: "BUY", StockSymbol: t.Symbol, Funds: t.Amount, } SendRabbitMessage(CommandEvent, CommandEvent.EventType) //Decode Request Body if err != nil { writeResponse(w, http.StatusBadRequest, "Request Body Is Invalid") return } //Validate Request Body AmountDec, err := decimal.NewFromString(t.Amount) if err != nil { writeResponse(w, http.StatusBadRequest, "Request Body Is Invalid") return } //Validate amount to buy if AmountDec.Cmp(zero) != 1 { writeResponse(w, http.StatusBadRequest, "Amount to buy is not a valid number") return } StockId := t.Symbol //Validate Stock Symbol if len(StockId) == 0 || len(StockId) > 3 { writeResponse(w, http.StatusBadRequest, "Symbol is Not Valid") return } //Get and Validate Quote var strPrice string var strExpiration string strPrice, strExpiration = getStockPrice(TransId, "true", UserId, StockId, Guid.String()) var quotePrice decimal.Decimal quotePrice, err = decimal.NewFromString(strPrice) if err != nil { writeResponse(w, http.StatusInternalServerError, "Quote Return is not Valid") return } if quotePrice.Cmp(zero) != 1 { writeResponse(w, http.StatusBadRequest, "Amount to buy is not a valid number: "+quotePrice.String()) return } //Verify Expiration Time ExpirationTime, err := time.Parse("2006-01-02 15:04:05 -0700 MST", strExpiration) if err != nil { writeResponse(w, http.StatusOK, "Expiration Conversion Error") return } //Check If User Exists db, uid, found, _ := getDatabaseUserId(UserId) if found == false { writeResponse(w, http.StatusBadRequest, "User Does Not Exist") return } //Calculate Stock To Buy toBuy := (AmountDec.Div(quotePrice)).IntPart() //Validate Buy Amount if toBuy < 1 { writeResponse(w, http.StatusBadRequest, "Cannot Buy less than 1 stock") return } strBuy := strconv.Itoa(int(toBuy)) //Add Pending Purchase for Amount var PurchaseId int rows, err := db.Query(addPendingPurchase, uid, t.Symbol, strBuy, strPrice, time.Now(), ExpirationTime) defer rows.Close() if err != nil { writeResponse(w, http.StatusInternalServerError, "Failed to Create Purchase") return } rows.Next() err = rows.Scan(&PurchaseId) if err != nil { writeResponse(w, http.StatusBadRequest, "Sale Id Request Failed") return } TimeToExpiration := (ExpirationTime.Sub(time.Now())) / time.Millisecond //Build Response rtnStruct := return_struct{false, PurchaseId, strPrice, toBuy, TimeToExpiration} strRtnStruct, err := json.Marshal(rtnStruct) //success writeResponse(w, http.StatusOK, string(strRtnStruct)) return }
func Quote(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) StockId := vars["symbol"] UserId := vars["id"] TransId := r.Header.Get("X-TransNo") if TransId == "" { TransId = "0" } //Audit UserCommand Guid := getNewGuid() CommandEvent := UserCommandEvent{ EventType: "UserCommandEvent", Guid: Guid.String(), OccuredAt: time.Now(), TransactionId: TransId, UserId: UserId, Service: "Command", Server: "B134", Command: "QUOTE", StockSymbol: StockId, Funds: "", } SendRabbitMessage(CommandEvent, CommandEvent.EventType) //Check Stock Symbol if len(StockId) == 0 || len(StockId) > 3 { writeResponse(w, http.StatusBadRequest, "Symbol is Not Valid") return } //Get Stock Price var strPrice string strPrice, _ = getStockPrice(TransId, "false", UserId, StockId, Guid.String()) //Verify Return Price var price decimal.Decimal price, err := decimal.NewFromString(strPrice) if err != nil { writeResponse(w, http.StatusBadRequest, "Quote Return: "+err.Error()) return } //Success var Output string = "The Quote For UserId " + UserId + " and StockId " + StockId + " returned " + price.String() writeResponse(w, http.StatusOK, Output) }