//Decode is the inverse operation of Encode. //Decode returns latitude, longitude, and whether or not they are both represented precisely as float64 types. func Decode(bucket int64) (float64, float64, bool) { var latitudeUnshifted, longitudeUnshifted decimal.Decimal var latitude, longitude float64 var err error var exact bool bucketString := strconv.FormatInt(bucket, 10) for len(bucketString) < 18 { bucketString = "0" + bucketString } latString, lonString := unzip(bucketString) latString = latString[0:3] + "." + latString[3:] lonString = lonString[0:3] + "." + lonString[3:] latitudeUnshifted, err = decimal.NewFromString(latString) longitudeUnshifted, err = decimal.NewFromString(lonString) if err != nil { fmt.Errorf("Error creating decimal from string") } latitudeUnshifted = latitudeUnshifted.Sub(decimal.NewFromFloat(90.0)) longitudeUnshifted = longitudeUnshifted.Sub(decimal.NewFromFloat(180.0)) latitude, exact = latitudeUnshifted.Float64() longitude, exact = longitudeUnshifted.Float64() return latitude, longitude, exact }
func Parse(s string) (time.Duration, error) { var d time.Duration var p parser if s == "0" { return d, nil } if s[len(s)-1] == 's' { switch c := s[len(s)-2]; c { case 'n': //ns p = parsers[0] case 'µ': //µs p = parsers[1] case 'm': //ms p = parsers[2] default: if '0' <= c && c <= '9' { //s p = parsers[3] } else { return d, ErrMalformed } } } else { return d, ErrMalformed } sub := p.re.FindStringSubmatch(s) // fmt.Println(len(sub), sub) switch len(sub) { case 5: i, _ := strconv.Atoi(sub[2]) d += time.Duration(i) * time.Hour i, _ = strconv.Atoi(sub[3]) d += time.Duration(i) * time.Minute f, err := decimal.NewFromString(sub[4]) if err != nil { panic(err) } f = f.Mul(decimal.New(int64(p.unit), 0)) d += time.Duration(f.IntPart()) case 3: f, err := decimal.NewFromString(sub[2]) if err != nil { panic(err) } f = f.Mul(decimal.New(int64(p.unit), 0)) d += time.Duration(f.IntPart()) default: return d, ErrMalformed } if sub[1] != "-" { return d, nil } else { return -d, nil } }
func AccountsUpdater(c *gin.Context) { acc_id, err := strconv.ParseInt(c.Param("accountId"), 10, 64) if err != nil { log.Fatal(err) } trans_id, err := strconv.ParseInt(c.PostForm("ID"), 10, 64) if err != nil { log.Printf("Invalid ID: %v - %v\n", trans_id, err) return } var account *Account for _, acc := range accounts { if acc.ID == acc_id { account = acc break } } var transaction Transaction for _, trans := range account.Transactions { if trans.ID == trans_id { transaction = trans } } transaction.Payee = c.PostForm("Payee") transaction.Memo = c.PostForm("Memo") debit, err := decimal.NewFromString(c.PostForm("Debit")) if err != nil { log.Printf("Invalid Debit %v\n", err) } else { transaction.Debit = debit } credit, err := decimal.NewFromString(c.PostForm("Credit")) if err != nil { log.Printf("Invalid Credit %v\n", err) } else { transaction.Credit = credit } for trans_key, trans := range account.Transactions { if trans.ID == trans_id { account.Transactions[trans_key] = transaction jsonResponse, err := json.Marshal(transaction) if err != nil { log.Printf("Json marshaling error: %v\n", err) return } c.JSON(http.StatusOK, jsonResponse) } } }
func Money(value interface{}, code string) (MoneyObject, error) { currency, found := CurrencyTypes[code] if !found { return MoneyObject{}, errors.New("Code not found.") } var money decimal.Decimal var moneyObject MoneyObject switch v := value.(type) { case string: m, err := decimal.NewFromString(v) if err != nil { return MoneyObject{}, err } money = m case float32: money = decimal.NewFromFloat(float64(v)) case float64: money = decimal.NewFromFloat(v) case int: money = decimal.NewFromFloat(float64(v)) default: return MoneyObject{}, errors.New("Value could not be translated.") } moneyObject.money = money moneyObject.currency = currency return moneyObject, nil }
func parseDecimal(lit string) (decimal.Decimal, error) { f, err := decimal.NewFromString(lit) if err != nil { return decimal.Zero, errors.New("Cannot parse recognized decimal: " + lit) } return f, nil }
func StringToDecimal(str string) decimal.Decimal { d, err := decimal.NewFromString(str) if err != nil { panic(err) } return d }
func TestTransactions(t *testing.T) { a := &Account{IsActive: true, CurrencyCode: "AUD"} credit10, _ := decimal.NewFromString("10.0") debit, _ := decimal.NewFromString("0.0") trans := Transaction{ Credit: credit10, Debit: debit, IsCleared: true, } a.AddTransaction(trans) total := a.GetTotal() if total.String() != credit10.String() { t.Errorf("Total not right, expected %v got %v", credit10, a.GetTotal()) } if a.GetClearedTotal().String() != credit10.String() { t.Error("Cleared Total not right") } credit, _ := decimal.NewFromString("0.0") debit, _ = decimal.NewFromString("5.0") trans.Credit = credit trans.Debit = debit trans.IsCleared = false a.AddTransaction(trans) if a.GetTotal().String() != debit.String() { t.Error("Total not right") } if a.GetClearedTotal().String() != credit10.String() { t.Error("Cleared total not right") } tr := a.GetTransactions() if len(tr) != 2 { t.Error("Number of transactions not right") } // log.Printf("%v\n", tr) }
func queryDecimal(fieldName string) decimal.Decimal { val, err := decimal.NewFromString(queryString(fieldName)) if err != nil { panic(err) } return val }
// NewNum initializes a Num from a BasicLit. Kind will hold the unit // the number portion is always treated as a float. func NewNum(lit *ast.BasicLit) (*Num, error) { val := lit.Value // TODO: scanner should remove unit kind := lit.Kind val = strings.TrimSuffix(lit.Value, token.Tokens[kind]) dec, err := decimal.NewFromString(val) return &Num{dec: dec, Unit: unitLookup(kind)}, err }
func (a *Account) ImportTransactions(r io.Reader) { csvr := csv.NewReader(r) csvr.LazyQuotes = true csvr.TrimLeadingSpace = true records, err := csvr.ReadAll() if err != nil { log.Println(err) } for k, record := range records { if k == 0 { continue } transDate, err := time.Parse("02/01/2006", record[1]) if err != nil { log.Println(err) } cleared := true reconciled := false credit, err := decimal.NewFromString(record[4]) if err != nil { log.Print(err) } debit, err := decimal.NewFromString(record[3]) if err != nil { log.Print(err) } trans := Transaction{ Credit: credit, Debit: debit, IsCleared: cleared, IsReconciled: reconciled, Payee: record[2], Date: transDate, } a.AddTransaction(trans) } }
func TestCurrencyDivisionByZero(t *testing.T) { fromUSD, err := decimal.NewFromString("0") if err != nil { t.Fatal(err) } f, _ := fromUSD.Float64() if f != 0 { oneD.Div(fromUSD) } }
func (ex *Exchange) normalizeCurrencyData(yahooData *yahooCurrencyResponse) (map[Currency]ExchangeRate, error) { data := make(map[Currency]ExchangeRate) for _, res := range yahooData.List.Resources { sym := res.Resource.Fields.Symbol // exp EUR=X if len(sym) != 5 { return nil, ErrCurrencyLength } cur, err := ParseCurrency(sym[:3]) if err != nil { if err == ErrCurrencyUnknown { continue } return nil, err } price := res.Resource.Fields.Price // extra check f, err := strconv.ParseFloat(price, 64) if err != nil { return nil, err } isZero := f == 0 fromUSD, err := decimal.NewFromString(price) if err != nil { return nil, err } toUSD := fromUSD if !isZero { toUSD = oneD.Div(fromUSD) } toUSD = oneD.Div(fromUSD) data[cur] = ExchangeRate{ FromUSD: fromUSD, ToUSD: toUSD, } } return data, nil }
func NewTSPCoord(id string, origLat string, origLon string, mode string) (*TSPCoord, error) { intId, err := strconv.Atoi(id) if err != nil { return nil, err } decimalLat, err := decimal.NewFromString(origLat) if err != nil { return nil, err } decimalLon, err := decimal.NewFromString(origLon) if err != nil { return nil, err } tspCoord := &TSPCoord{Id: intId, OrigLat: origLat, OrigLon: origLon, Coord: NewCoord(decimalLat, decimalLon), Duplicates: NewTSPCoordList(), CostTable: NewCostTable()} switch { case mode == "EUC_2D": tspCoord.fromEUC2D() } tspCoord.CoordHash = fmt.Sprintf("%s_%s", origLat, origLon) return tspCoord, nil }
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) }
func main() { account := bank.CreateAccount(1) account.Deposit(decimal.NewFromFloat(1000.50)) reader := bufio.NewReader(os.Stdin) fmt.Println("Welcome to the Go ATM service!\n") for { fmt.Println("1. View current balance.") fmt.Println("2. Withdraw.") fmt.Println("3. Exit.") actionStr, _ := reader.ReadString('\n') action, _ := strconv.ParseInt(strings.TrimSpace(actionStr), 10, 32) switch action { case 1: fmt.Println(account.GetBalance().String()) case 2: fmt.Println("\nWithdraw amount:") amountStr, _ := reader.ReadString('\n') amount, _ := decimal.NewFromString(strings.TrimSpace(amountStr)) _, err := account.Withdraw(amount) if err != nil { fmt.Println(err) } case 3: os.Exit(0) } } }
// Use github.com/shopspring/decimal as real-world database/sql custom type // to test against. func TestConnQueryDatabaseSQLDriverValuer(t *testing.T) { t.Parallel() conn := mustConnect(t, *defaultConnConfig) defer closeConn(t, conn) expected, err := decimal.NewFromString("1234.567") if err != nil { t.Fatal(err) } var num decimal.Decimal err = conn.QueryRow("select $1::decimal", expected).Scan(&num) if err != nil { t.Fatalf("Scan failed: %v", err) } if !num.Equals(expected) { t.Errorf("Expected num to be %v, but it was %v", expected, num) } ensureConnValid(t, conn) }
func (s *SlackSession) handleMessage(User string, Channel string, msg *slack.Msg) { tx, err := s.Db.Begin() if err != nil { goto fail } defer tx.Rollback() // Check user type; ignore bots { if msg.SubType == "bot_message" { return } var is_bot bool if err = tx.QueryRow("select user_is_bot from users where user_id = $1 and team_id = $2", User, s.TeamID).Scan(&is_bot); err != nil { s.log.WithError(err).Warn("Failed to read row") goto fail } if is_bot { s.log.Debug("Ignoring message; from bot") return } } if match := rxProposal.FindStringSubmatch(msg.Text); match != nil { s.log.WithField("matchgroups", fmt.Sprintf("%#v", match)).Info("Saw proposal") topic := match[1] comment := match[2] _, err = tx.Exec( "INSERT INTO topics (team_id, topic_channel, topic_name, topic_comment) "+ "VALUES ($1, $2, $3, nullif($4,''))", s.TeamID, Channel, topic, comment) if err != nil { // TODO: report error in channel s.log.WithError(err).Info("Failed to insert proposal") goto fail } pmp := slack.NewPostMessageParameters() pmp.AsUser = true //pmp.Username = s.rtm.GetInfo().User.Name _, _, err = s.rtm.PostMessage(Channel, fmt.Sprintf("Voting is now open on %s", topic), pmp) if err != nil { log.WithError(err).Info("Failed to post voting open message") } } else if match := rxVote.FindStringSubmatch(msg.Text); match != nil { var value decimal.Decimal topic := match[2] log := s.log.WithFields(log.Fields{ "topic": topic, "user": User, "channel": msg.Channel, "user_msg": msg.Text, }) if value, err = decimal.NewFromString(match[1]); err != nil { log.WithError(err).Info("Failed to parse vote value") return } comment := match[3] _, err = tx.Exec( "INSERT INTO votes (team_id, topic_name, user_id, vote_value, vote_comment) "+ "VALUES ($1, $2, $3, $4, nullif($5, '')) "+ "ON CONFLICT (topic_name, team_id, user_id) "+ "DO UPDATE SET (vote_value, vote_comment) = ($4, nullif($5, ''))", s.TeamID, topic, User, value, comment) if err != nil { log.WithError(err).Info("Failed to insert vote") } log.WithField("matchgroups", fmt.Sprintf("%#v", match)).Info("Saw vote") } else if match := s.rxAtMessage.FindStringSubmatch(msg.Text); match != nil { args, err := shlex.Split(match[1], true) pmp := slack.NewPostMessageParameters() pmp.AsUser = true pmp.EscapeText = false user_pfx := fmt.Sprintf("<@%s>: ", msg.User) if err != nil || len(args) < 1 { s.rtm.PostMessage(Channel, user_pfx+" Syntax error: %s"+err.Error(), pmp) return } switch strings.ToLower(args[0]) { case "howdy": s.rtm.PostMessage(Channel, user_pfx+" Howdy neighbor!", pmp) case "status": if len(args) < 2 { topics := []map[string]interface{}{} rows, err := tx.Query( "SELECT topic_name, COALESCE(topic_comment, ''), COUNT(user_id), SUM(vote_value) "+ "FROM topics NATURAL LEFT JOIN (votes NATURAL JOIN users) "+ "WHERE topic_open AND team_id = $1 AND topic_channel = $2 "+ "GROUP BY topic_name, topic_channel, team_id, topic_comment", s.TeamID, Channel) if err != nil { log.WithError(err).Error("Failed to query topics") return } for rows.Next() { var ( name, comment string count int sum decimal.Decimal ) rows.Scan(&name, &comment, &count, &sum) topics = append(topics, map[string]interface{}{ "name": name, "comment": comment, "nvotes": count, "total": sum, }) } buffer := &bytes.Buffer{} topicSummary.Execute(buffer, topics) s.rtm.PostMessage(Channel, buffer.String(), pmp) } default: s.rtm.PostMessage(Channel, fmt.Sprintf("%s You seem confused; you said `%#v`", user_pfx, args), pmp) } } tx.Commit() return fail: } /* Sample message var foo = &slack.MessageEvent{Msg: slack.Msg{ Type: "message", Channel: "C0KGNAP7A", User: "******", Text: "More testage", Timestamp: "1454444512.000011", IsStarred: false, PinnedTo: []string(nil), Attachments: []slack.Attachment(nil), Edited: (*slack.Edited)(nil), SubType: "", Hidden: false, DeletedTimestamp: "", EventTimestamp: "", BotID: "", Username: "", Icons: (*slack.Icon)(nil), Inviter: "", Topic: "", Purpose: "", Name: "", OldName: "", Members: []string(nil), File: (*slack.File)(nil), Upload: false, Comment: (*slack.Comment)(nil), ItemType: "", ReplyTo: 0, Team: "T06RWKEF3"}} */ func (s *SlackSession) updateUser(user slack.User) { tx, err := s.Db.Begin() if err != nil { goto fail } defer tx.Rollback() if _, err = tx.Exec( "INSERT INTO users (team_id, user_id, user_name, user_is_bot) VALUES ($3, $2, $1, $4) "+ "ON CONFLICT (team_id, user_id) DO UPDATE SET (user_name, user_is_bot) = ($1, $4)", user.Name, user.ID, s.TeamID, user.IsBot); err != nil { goto fail } if err = tx.Commit(); err != nil { goto fail } return fail: if err != nil { s.log.WithError(err).WithField("user", user.ID).Error("Failed to refresh user in db") } } func (s *SlackSession) updateTeam(team *slack.Team) { tx, err := s.Db.Begin() if err != nil { goto fail } defer tx.Rollback() if _, err = tx.Exec("UPDATE teams SET (team_name) = ($1) WHERE team_id = $2", team.Name, team.ID); err != nil { goto fail } if err = tx.Commit(); err != nil { goto fail } return fail: if err != nil { s.log.WithError(err).Error("Failed to refresh team in db") } }
// ParseAmount parses `in` into an Amount value func ParseAmount(in string) (ret Amount, err error) { dec, err := decimal.NewFromString(in) ret = Amount{dec} return }
func init() { Const1K, _ = decimal.NewFromString("1000") ConstNegative1K, _ = decimal.NewFromString("-1000") }
// DecodeDecimal decodes a transit big decimal into decimal.Decimal. func DecodeDecimal(d Decoder, x interface{}) (interface{}, error) { s := x.(string) return decimal.NewFromString((s)) }
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 } }
// ConvertStringAt converts the decimal value (represented as a string) to the // given currency using the exchange rate from the date specificied. func (c *Converter) ConvertStringAt(value string, from, to Currency, at time.Time) (decimal.Decimal, error) { v, _ := decimal.NewFromString(value) return c.genConvert(v, from, to, &at) }
// ConvertString converts the decimal value (represented as a string) to the // given currency. func (c *Converter) ConvertString(value string, from, to Currency) (decimal.Decimal, error) { v, _ := decimal.NewFromString(value) return c.genConvert(v, from, to, nil) }
func Add(w http.ResponseWriter, r *http.Request) { zero, _ := decimal.NewFromString("0") type add_struct struct { Amount string } type return_struct struct { Error bool Amount string UserId string } vars := mux.Vars(r) UserId := vars["id"] TransId := r.Header.Get("X-TransNo") if TransId == "" { TransId = "0" } decoder := json.NewDecoder(r.Body) var t add_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: "ADD", StockSymbol: "", Funds: t.Amount, } SendRabbitMessage(CommandEvent, CommandEvent.EventType) if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()) return } AmountDec, err := decimal.NewFromString(t.Amount) if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()) return } //Get user id from Database db := getDatabasePointerForUser(UserId) //Amount to add is invalid if AmountDec.Cmp(zero) != 1 { writeResponse(w, http.StatusBadRequest, "Amount to add is not a valid number") return } _, err = db.Exec(addOrCreateUser, UserId, t.Amount, time.Now()) //Failed to Create Account if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()) return } //Build Response rtnStruct := return_struct{false, t.Amount, UserId} strRtnStruct, err := json.Marshal(rtnStruct) //Success writeResponse(w, http.StatusOK, string(strRtnStruct)) return }
func Sell(w http.ResponseWriter, r *http.Request) { zero, _ := decimal.NewFromString("0") type sell_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" } //Decode Body decoder := json.NewDecoder(r.Body) var t sell_struct err := decoder.Decode(&t) //Audit UserCommand Guid := getNewGuid() OccuredAt := time.Now() CommandEvent := UserCommandEvent{ EventType: "UserCommandEvent", Guid: Guid.String(), OccuredAt: OccuredAt, TransactionId: TransId, UserId: UserId, Service: "Command", Server: Hostname, Command: "SELL", StockSymbol: t.Symbol, Funds: t.Amount, } SendRabbitMessage(CommandEvent, CommandEvent.EventType) if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()) return } //get User Account Information db, id, found, _ := getDatabaseUserId(UserId) if found == false { writeResponse(w, http.StatusOK, "User Account Does Not Exist") return } //Check amount AmountDec, err := decimal.NewFromString(t.Amount) if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()) return } if AmountDec.Cmp(zero) != 1 { writeResponse(w, http.StatusBadRequest, "Amount to sell is not a valid number") return } //Check Stock Symbol StockId := t.Symbol if len(StockId) == 0 || len(StockId) > 3 { writeResponse(w, http.StatusBadRequest, "Symbol is Not Valid") return } //Get and Verify 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.StatusBadRequest, err.Error()) return } if quotePrice.Cmp(zero) != 1 { writeResponse(w, http.StatusBadRequest, "Quote is not a valid number") 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 } //Calculate Amount to Sell toSell := (AmountDec.Div(quotePrice)).IntPart() if toSell < 1 { writeResponse(w, http.StatusOK, "Can't Sell less than 1 Stock") return } strSell := strconv.Itoa(int(toSell)) //Create Pending Sale var SaleId int rows, err := db.Query(addPendingSale, id, t.Symbol, strSell, strPrice, time.Now(), ExpirationTime) defer rows.Close() if err != nil { writeResponse(w, http.StatusBadRequest, "Add pending Sale; "+err.Error()) return } TimeToExpiration := (ExpirationTime.Sub(time.Now())) / time.Millisecond rows.Next() err = rows.Scan(&SaleId) //Build Response rtnStruct := return_struct{false, SaleId, strPrice, toSell, TimeToExpiration} strRtnStruct, err := json.Marshal(rtnStruct) //success writeResponse(w, http.StatusOK, string(strRtnStruct)) return }
func CreateSellTrigger(w http.ResponseWriter, r *http.Request) { type trigger_struct struct { Amount string Price string } vars := mux.Vars(r) UserId := vars["id"] Symbol := vars["symbol"] TransId := r.Header.Get("X-TransNo") if TransId == "" { TransId = "0" } decoder := json.NewDecoder(r.Body) var t trigger_struct err := decoder.Decode(&t) //Audit UserCommand Guid := getNewGuid() OccuredAt := time.Now() if t.Amount == "" && t.Price == "" { CommandEvent := UserCommandEvent{ EventType: "UserCommandEvent", Guid: Guid.String(), OccuredAt: OccuredAt, TransactionId: TransId, UserId: UserId, Service: "Command", Server: Hostname, Command: "SET_BUY_AMOUNT", StockSymbol: Symbol, Funds: "", } SendRabbitMessage(CommandEvent, CommandEvent.EventType) writeResponse(w, http.StatusBadRequest, "Invalid Request Body") return } if t.Amount != "" { CommandEvent := UserCommandEvent{ EventType: "UserCommandEvent", Guid: Guid.String(), OccuredAt: OccuredAt, TransactionId: TransId, UserId: UserId, Service: "Command", Server: Hostname, Command: "SET_SELL_AMOUNT", StockSymbol: Symbol, Funds: "", } SendRabbitMessage(CommandEvent, CommandEvent.EventType) if err != nil { writeResponse(w, http.StatusBadRequest, "Invalid Request Body") return } db, uid, found, _ := getDatabaseUserId(UserId) if !found { writeResponse(w, http.StatusBadRequest, "User Account Does Not Exist") return } _, err := decimal.NewFromString(t.Amount) if err != nil { writeResponse(w, http.StatusBadRequest, "Amount Is Not A Valid Number") return } _, err = db.Exec(addSellTrigger, uid, Symbol, t.Amount, time.Now()) if err != nil { writeResponse(w, http.StatusBadRequest, "addSellTrigger: "+err.Error()) return } //success writeResponse(w, http.StatusOK, "Sell Trigger Created") return } else { CommandEvent := UserCommandEvent{ EventType: "UserCommandEvent", Guid: Guid.String(), OccuredAt: OccuredAt, TransactionId: TransId, UserId: UserId, Service: "Command", Server: Hostname, Command: "SET_SELL_TRIGGER", StockSymbol: Symbol, Funds: "", } SendRabbitMessage(CommandEvent, CommandEvent.EventType) if err != nil { writeResponse(w, http.StatusBadRequest, "Invalid Request Body") return } db, uid, found, _ := getDatabaseUserId(UserId) if !found { writeResponse(w, http.StatusBadRequest, "User Account Not Found") return } _, err := decimal.NewFromString(t.Price) if err != nil { writeResponse(w, http.StatusBadRequest, "Price Is Not A Valid Number") return } getPendingTriggerRows, err := db.Query(getPendingTriggerId, uid, Symbol, "sell") defer getPendingTriggerRows.Close() if err != nil { writeResponse(w, http.StatusBadRequest, "getPendingTriggerId: "+err.Error()) return } var id int found = false for getPendingTriggerRows.Next() { found = true err = getPendingTriggerRows.Scan(&id) } if found == false { writeResponse(w, http.StatusBadRequest, "No recent SET_SELL_AMOUNT commands Issued") return } _, err = db.Exec(setSellTrigger, id, uid, t.Price, time.Now()) if err != nil { writeResponse(w, http.StatusBadRequest, "setSellTrigger: "+err.Error()) return } //Send Trigger Message Trigger := TriggerEvent{ TriggerType: "sell", UserId: UserId, TransactionId: TransId, UpdatedAt: time.Now(), } SendRabbitMessage(Trigger, "sell") //success writeResponse(w, http.StatusOK, "Sell Trigger Set") return } }
func UpdateSale(w http.ResponseWriter, r *http.Request) { zero, _ := decimal.NewFromString("0") vars := mux.Vars(r) UserId := vars["id"] TransId := vars["PurchaseId"] //get User Account Information db, uid, found, _ := getDatabaseUserId(UserId) if found == false { writeResponse(w, http.StatusOK, "User Account Does Not Exist") return } Guid := getNewGuid() //Find last Sell Command LatestPendingrows, err := db.Query(getLatestPendingSale, uid) defer LatestPendingrows.Close() if err != nil { writeResponse(w, http.StatusOK, "Error Getting Last Sale: "+err.Error()) return } var id string var stock string var num_shares int var share_price string var requested_at time.Time var expires_at time.Time found = false for LatestPendingrows.Next() { found = true err = LatestPendingrows.Scan(&id, &uid, &stock, &num_shares, &share_price, &requested_at, &expires_at) } if found == false { writeResponse(w, http.StatusOK, "No Recent Sell Commands") return } strOldPrice := strings.TrimPrefix(share_price, "$") strOldPrice = strings.Replace(strOldPrice, ",", "", -1) OldPrice, err := decimal.NewFromString(strOldPrice) if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()+strOldPrice) return } //Get and Verify Quote var strPrice string strPrice, _ = getStockPrice(TransId, "true", UserId, stock, Guid.String()) var quotePrice decimal.Decimal quotePrice, err = decimal.NewFromString(strPrice) if err != nil { writeResponse(w, http.StatusBadRequest, err.Error()) return } if quotePrice.Cmp(zero) != 1 { writeResponse(w, http.StatusBadRequest, "Quote is not a valid number") return } totalAmount := decimal.New(int64(num_shares), 0).Mul(OldPrice) newShareNum := totalAmount.Div(quotePrice).IntPart() diffShares := int(newShareNum) - num_shares _, err = db.Exec(updateSale, TransId, int(newShareNum), strPrice, int(diffShares), time.Now().Add(time.Duration(60)*time.Second)) if err != nil { writeResponse(w, http.StatusBadRequest, "Unable to update Sale") return } type return_struct struct { Error bool SaleId string Price string NumShares int64 Expiration time.Duration } //Build Response rtnStruct := return_struct{false, id, strPrice, newShareNum, -1} strRtnStruct, err := json.Marshal(rtnStruct) writeResponse(w, http.StatusOK, string(strRtnStruct)) 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 PerformBuyTrigger(w http.ResponseWriter, r *http.Request) { zero, _ := decimal.NewFromString("0") vars := mux.Vars(r) UserId := vars["id"] StockId := vars["symbol"] TransId := r.Header.Get("X-TransNo") if TransId == "" { TransId = "0" } type trigger_struct struct { TriggerId string } decoder := json.NewDecoder(r.Body) var t trigger_struct err := decoder.Decode(&t) if err != nil { } Guid := getNewGuid() //Check If User Exists db, uid, found, _ := getDatabaseUserId(UserId) if !found { //error return } //Get A Quote var strPrice string strPrice, _ = getStockPrice(TransId, "false", 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 { Error := ErrorEvent{ EventType: "ErrorEvent", Guid: Guid.String(), OccuredAt: time.Now(), TransactionId: TransId, UserId: UserId, Service: "API", Server: Hostname, Command: "ADD", StockSymbol: "", Funds: strPrice, FileName: "", ErrorMessage: "Quote is not greater than 0", } SendRabbitMessage(Error, Error.EventType) //writeResponse(w, http.StatusBadRequest, "Amount to buy is not a valid number") return } //Get Trigger Information rows, err := db.Query(getTriggerById, t.TriggerId) defer rows.Close() if err != nil { //error return } var id int var stock string var trigger_type string var trigger_price string var num_shares int var created_at time.Time found = false for rows.Next() { found = true err = rows.Scan(&id, &uid, &stock, &trigger_type, &trigger_price, &num_shares, &created_at) } if err != nil { //error return } if !found { //error return } trigger_price = strings.Trim(trigger_price, "$") trigger_price = strings.Replace(trigger_price, ",", "", -1) trigger_priceDec, err := decimal.NewFromString(trigger_price) if quotePrice.Cmp(trigger_priceDec) != -1 { //error return } //Commit trigger at price _, err = db.Exec(performBuyTrigger, id, strPrice) if err != nil { //error return } }
func (d *FIXDecimal) Read(bytes []byte) (err error) { d.Decimal, err = decimal.NewFromString(string(bytes)) return }