-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlbcmonitor.go
181 lines (160 loc) · 4.33 KB
/
lbcmonitor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package main
import (
"encoding/json"
"fmt"
flags "github.com/jessevdk/go-flags"
"log"
"net/http"
"os"
"strconv"
"text/tabwriter"
)
const (
sellPage = "https://localbitcoins.com/sell-bitcoins-online/US/united-states/cash-deposit/.json"
buyPage = "https://localbitcoins.com/buy-bitcoins-online/US/united-states/cash-deposit/.json"
)
type Options struct {
Buying bool `long:"buy" description:"Switch to buying mode instead of selling."`
XBTAmount float64 `long:"xbt" description:"Amount of XBT that requires conversion to fiat."`
FiatAmount float64 `long:"fiat" description:"Amount of fiat needed from the conversion of given XBT."`
XBTPrice float64 `long:"xbtprice" description:"Price of 1 XBT that the software should alert at."`
Pages uint `long:"pages" description:"Number of pages to follow. Default 5."`
priceMonitor bool
}
var opts = new(Options)
var w = new(tabwriter.Writer)
func main() {
_, err := flags.Parse(opts)
if err != nil {
if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
return
}
os.Exit(1)
}
if opts.XBTAmount == 0 && opts.FiatAmount == 0 { // invalid/price monitoring
if opts.XBTPrice == 0 { // invalid
fmt.Fprintln(os.Stderr, "Invalid arguments")
os.Exit(1)
} else {
opts.priceMonitor = true
}
} else if opts.XBTAmount == 0 || opts.FiatAmount == 0 { // insufficient args
fmt.Fprintln(os.Stderr, "Invalid arguments")
os.Exit(1)
}
if opts.Pages == 0 {
opts.Pages = 5
}
// Format in tab-separated columns with a tab stop of 8.
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
fmt.Fprintln(w, "Rate\tMin\tMax\tBanks\tLink")
fmt.Fprintln(w, "----\t---\t---\t-----\t----")
if opts.Buying {
process(buyPage)
} else {
process(sellPage)
}
w.Flush()
}
func process(jsonURL string) {
res, err := http.Get(jsonURL)
if err != nil {
fmt.Fprintf(os.Stderr, "got HTTP error %v\n", err)
os.Exit(1)
}
if res.StatusCode != 200 {
fmt.Fprintf(os.Stderr, "got status code %d\n", res.StatusCode)
os.Exit(1)
}
m := new(MainJson)
err = json.NewDecoder(res.Body).Decode(m)
res.Body.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "json decode failed: %v\n", err)
os.Exit(1)
}
ads := m.Data.AdList
for i, ad := range ads {
var maxAmount, minAmount float64
if ad.Data.MaxAmount != "" {
maxAmount, err = strconv.ParseFloat(ad.Data.MaxAmount, 64)
if err != nil {
log.Printf("maxAmount decode for ad #%d failed: %v\n", i, err)
}
}
if ad.Data.MinAmount != "" {
minAmount, err = strconv.ParseFloat(ad.Data.MinAmount, 64)
if err != nil {
log.Printf("minAmount decode for ad #%d failed: %v\n", i, err)
}
}
price, err := strconv.ParseFloat(ad.Data.Price, 64)
if err != nil {
log.Printf("price decode for ad #%d failed: %v\n", i, err)
}
bankName := ad.Data.BankName
url := ad.Actions.PublicView
if opts.priceMonitor {
var cond bool
if !opts.Buying { // want highest selling price
cond = price >= opts.XBTPrice
} else { // want lowest selling price
cond = price <= opts.XBTPrice
}
if cond {
fmt.Fprintf(w, "%.2f\t%.0f\t%.0f\t%s\t%s\n", price, minAmount,
maxAmount, bankName, url)
}
} else {
if maxAmount < opts.FiatAmount {
continue
}
if minAmount > opts.FiatAmount {
continue
}
calcFiat := opts.XBTAmount * price
var cond bool
if !opts.Buying { // want max fiat
cond = calcFiat >= opts.FiatAmount
} else { // want lowest fiat
cond = calcFiat <= opts.FiatAmount
}
if cond {
fmt.Fprintf(w, "%.2f\t%.0f\t%.0f\t%s\t%s\n", price, minAmount,
maxAmount, bankName, url)
}
}
}
opts.Pages -= 1
if opts.Pages > 0 && m.Pagination.Next != "" { // we can still go over more
process(m.Pagination.Next)
}
}
type MainJson struct {
Pagination PaginationJson `json:"pagination"`
Data DataJson `json:"data"`
}
type PaginationJson struct {
Next string `json:"next"`
}
type DataJson struct {
AdList []AdJson `json:"ad_list"`
}
type AdJson struct {
Data AdDataJson `json:"data"`
Actions AdActionsJson `json:"actions"`
}
type AdActionsJson struct {
PublicView string `json:"public_view"`
}
type AdDataJson struct {
Price string `json:"temp_price"`
BankName string `json:"bank_name"`
MinAmount string `json:"min_amount"`
MaxAmount string `json:"max_amount"`
Message string `json:"msg"`
}
type result struct {
price float64
url string
}