31
|
1 package main
|
|
2
|
|
3 import (
|
|
4 "bytes"
|
|
5 "encoding/csv"
|
|
6 "fmt"
|
|
7 "io"
|
|
8 "io/ioutil"
|
|
9 "log"
|
|
10 "math"
|
|
11 "strconv"
|
|
12 "strings"
|
|
13 )
|
|
14
|
|
15 const debug = false
|
|
16
|
|
17 func main() {
|
|
18 n, m := 20, 14
|
|
19 var x, xl, xh []float64
|
|
20 var date []string
|
|
21
|
|
22 // Read Exchange-data
|
|
23 content, err := ioutil.ReadFile("/Users/takayuki/Downloads/USDJPY.csv")
|
|
24 if err != nil {
|
|
25 log.Fatal(err)
|
|
26 }
|
|
27
|
|
28 r := csv.NewReader(bytes.NewReader(content))
|
|
29 for {
|
|
30 record, err := r.Read()
|
|
31 if err == io.EOF {
|
|
32 break
|
|
33 }
|
|
34 if err != nil {
|
|
35 log.Fatal(err)
|
|
36 }
|
|
37
|
|
38 f, err := strconv.ParseFloat(record[4], 64)
|
|
39 if err != nil {
|
|
40 continue
|
|
41 }
|
|
42 x = append(x, f)
|
|
43
|
|
44 f, err = strconv.ParseFloat(record[3], 64)
|
|
45 xl = append(xl, f)
|
|
46
|
|
47 f, err = strconv.ParseFloat(record[2], 64)
|
|
48 xh = append(xh, f)
|
|
49
|
|
50 date = append(date, strings.ReplaceAll(record[0], "/", "-"))
|
|
51 }
|
|
52
|
|
53 // Calc Moving-Average
|
|
54 xa := make([]float64, len(x))
|
|
55 for i := n; i < len(x); i++ {
|
|
56 for j := 0; j < n; j++ {
|
|
57 xa[i] += x[i-j]
|
|
58 }
|
|
59 xa[i] /= float64(n)
|
|
60 }
|
|
61
|
|
62 // Calc Variance & SD
|
|
63 v := make([]float64, len(x))
|
|
64 sd := make([]float64, len(x))
|
|
65 for i := n; i < len(x); i++ {
|
|
66 // variance
|
|
67 for j := 0; j < n; j++ {
|
|
68 v[i] += (x[i-j] - xa[i-j]) * (x[i-j] - xa[i-j])
|
|
69 }
|
|
70 v[i] /= float64(n)
|
|
71
|
|
72 // standard deviation
|
|
73 sd[i] = math.Sqrt(v[i])
|
|
74 }
|
|
75
|
|
76 // Calc Bollinger-Bands
|
|
77 bb1 := make([]float64, len(x))
|
|
78 bb2 := make([]float64, len(x))
|
|
79 for i := n * 2; i < len(x); i++ {
|
|
80 bb1[i], bb2[i] = x[i] - sd[i], x[i] + sd[i]
|
|
81 }
|
|
82
|
|
83 // Calc RSI
|
|
84 rsi := make([]float64, len(x))
|
|
85 for i := m; i < len(x); i++ {
|
|
86 var ru, rd float64
|
|
87 for j := 0; j < m; j++ {
|
|
88 z := x[i-j-1] - x[i-j]
|
|
89 if z > 0 {
|
|
90 ru += z
|
|
91 } else {
|
|
92 rd += -z
|
|
93 }
|
|
94 }
|
|
95 rsi[i] = rd / (rd + ru) * 100
|
|
96 }
|
|
97
|
|
98 // Make Graph
|
|
99 // [chart.svg]
|
|
100 w, h := 800, 600
|
|
101
|
|
102 term := 200
|
|
103 min, max := 200.0, 1.0
|
|
104 for i := len(x) - term; i < len(x); i++ {
|
|
105 min = math.Min(min, x[i])
|
|
106 max = math.Max(max, x[i])
|
|
107 min = math.Min(min, bb1[i])
|
|
108 max = math.Max(max, bb2[i])
|
|
109 }
|
|
110 sx := float64(w) / float64(term)
|
|
111 sy := float64(h) / (max - min)
|
|
112
|
|
113 svg := fmt.Sprintf("<svg xmlns='http://www.w3.org/2000/svg' width='%d' height='%d'>\n", w, h)
|
|
114 for y := int(min); y < int(max) + 1; y++ {
|
|
115 svg += make_line(h, 0, float64(y), w, float64(y), min, 1.0, sy, "gray", 0.2)
|
|
116 svg += make_label(h, 10, y, min, 1.0, sy, fmt.Sprintf("%d", y))
|
|
117 }
|
|
118 for i, j, lm := len(x) - term, 0, ""; i < len(x); i, j = i + 1, j + 1 {
|
|
119 if !strings.EqualFold(lm, date[i][5:7]) {
|
|
120 svg += make_line(h, j, 0.0, j, float64(h), 0, sx, 1.0, "gray", 0.2)
|
|
121 svg += make_label(h, j, 20, 0, sx, 1.0, date[i][0:7])
|
|
122 lm = date[i][5:7]
|
|
123 }
|
|
124 }
|
|
125
|
|
126 for i, j := len(x) - term, 1; i < len(x); i, j = i + 1, j + 1 {
|
|
127 svg += make_line(h, j-1, x[i-1], j, x[i], min, sx, sy, "black", 1.5)
|
|
128 svg += make_line(h, j-1, xa[i-1], j, xa[i], min, sx, sy, "green", 0.7)
|
|
129 svg += make_line(h, j-1, bb1[i-1], j, bb1[i], min, sx, sy, "red", 0.2)
|
|
130 svg += make_line(h, j-1, bb2[i-1], j, bb2[i], min, sx, sy, "blue", 0.2)
|
|
131 }
|
|
132 svg += fmt.Sprint("</svg>\n")
|
|
133 if err := ioutil.WriteFile("chart.svg", []byte(svg), 0644); err != nil {
|
|
134 log.Fatal(err)
|
|
135 }
|
|
136
|
|
137 // [rsi.svg]
|
|
138 w, h = w, 150
|
|
139 sy = float64(h) / 100
|
|
140 svg = fmt.Sprintf("<svg xmlns='http://www.w3.org/2000/svg' width='%d' height='%d'>\n", w, h)
|
|
141 svg += make_line(h, 0, 30.0, w, 30.0, 0, 1.0, sy, "gray", 0.2)
|
|
142 svg += make_label(h, 10, 30, 0, 1.0, sy, fmt.Sprintf("30%%"))
|
|
143 svg += make_line(h, 0, 50.0, w, 50.0, 0, 1.0, sy, "gray", 0.2)
|
|
144 svg += make_label(h, 10, 50, 0, 1.0, sy, fmt.Sprintf("50%%"))
|
|
145 svg += make_line(h, 0, 70.0, w, 70.0, 0, 1.0, sy, "gray", 0.2)
|
|
146 svg += make_label(h, 10, 70, 0, 1.0, sy, fmt.Sprintf("70%%"))
|
|
147
|
|
148 for i, j, lm := len(x) - term, 0, ""; i < len(x); i, j = i + 1, j + 1 {
|
|
149 if !strings.EqualFold(lm, date[i][5:7]) {
|
|
150 svg += make_line(h, j, 0.0, j, float64(h), 0, sx, 1.0, "gray", 0.2)
|
|
151 svg += make_label(h, j, 20, 0, sx, 1.0, date[i][0:7])
|
|
152 lm = date[i][5:7]
|
|
153 }
|
|
154 }
|
|
155
|
|
156 for i, j := len(x) - term, 1; i < len(x); i, j = i + 1, j + 1 {
|
|
157 svg += make_line(h, j-1, rsi[i-1], j, rsi[i], 0, sx, sy, "black", 1.5)
|
|
158 }
|
|
159 svg += fmt.Sprint("</svg>\n")
|
|
160 if err := ioutil.WriteFile("rsi.svg", []byte(svg), 0644); err != nil {
|
|
161 log.Fatal(err)
|
|
162 }
|
|
163
|
|
164 // Make Html
|
|
165 html := "<html><body>"
|
|
166 html += "<h2>Daily Chart</h2>"
|
|
167 html += "<img src='chart.svg' />"
|
|
168 html += "<h2>RSI</h2>"
|
|
169 html += "<img src='rsi.svg' />"
|
|
170 html += "</body><html>"
|
|
171 if err := ioutil.WriteFile("fx.html", []byte(html), 0644); err != nil {
|
|
172 log.Fatal(err)
|
|
173 }
|
|
174
|
|
175 // Print Data
|
|
176 if false {
|
|
177 fmt.Println("[j] n x bb1 bb2 rsi | n x bb1 bb2")
|
|
178 fmt.Println("---")
|
|
179 for i, j := len(x) - term, 0; i < len(x); i++ {
|
|
180 fmt.Printf("[%04d] %04d %5.2f %5.2f %5.2f %3.1f | ", j, i, x[i], bb1[i], bb2[i], rsi[i])
|
|
181 fmt.Printf("%04.0f %5.2f %5.2f %5.2f ", float64(i) * sx, (x[i] - min) * sy, (bb1[i] - min) * sy, (bb2[i] - min) * sy)
|
|
182 fmt.Println()
|
|
183 j++
|
|
184 }
|
|
185 fmt.Println("---")
|
|
186 fmt.Printf("min=%5.2f max=%5.2f\n", min, max)
|
|
187 }
|
|
188 }
|
|
189
|
|
190 func make_line(h, x1 int, y1 float64, x2 int, y2 float64, os, sx, sy float64, c string, sw float64) string {
|
|
191 x1, y1 = int(float64(x1) * sx), (y1 - os) * sy
|
|
192 x2, y2 = int(float64(x2) * sx), (y2 - os) * sy
|
|
193 y1, y2 = float64(h) - y1, float64(h) - y2
|
|
194 return fmt.Sprintf("<line x1='%d' y1='%d' x2='%d' y2='%d' stroke='%s' stroke-width='%0.1f' />\n", x1, int(y1), x2, int(y2), c, sw)
|
|
195 }
|
|
196
|
|
197 func make_label(h, x, y int, os, sx, sy float64, label string) string {
|
|
198 x = int(float64(x) * sx)
|
|
199 y = int((float64(y) - os) * sy)
|
|
200 y = h - y
|
|
201 return fmt.Sprintf("<text x='%d' y='%d'>%s</text>", x, y, label)
|
|
202 }
|
|
203
|