-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtradelog
299 lines (257 loc) · 7.37 KB
/
tradelog
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#!/bin/sh
# IOS project 1
# author: Patrik Korytar
# school: FIT VUT
# date: 28.3.2021
export POSIXLY_CORRECT=yes
export LC_ALL=C
### FUNCTIONS
# print help
print_help()
{
echo "Usage: ./tradelog [-h|--help]"
echo " ./tradelog [FILTER] [COMMAND] [LOG [LOG [...]]"
echo "Analyze stock-exchange records."
echo ""
echo "Options:"
echo " -h / --help -- print help"
echo ""
echo "Filters:"
echo " -a DATETIME -- print just records after this date and time"
echo " -b DATETIME -- print just records before this date and time"
echo " -t TICKER -- print just this ticker (multiple can be set)"
echo " -w WIDTH -- set width of histogram / graph"
echo ""
echo "Commands (can be one of):"
echo " list-tick -- list all tickers"
echo " profit -- print overall profit from all positions"
echo " pos -- list values of current tickers' positions"
echo " last-price -- list last known tickers' prices"
echo " hist-ord -- show histogram of number of tickers' transactions"
echo " graph-pos -- show graph of values of current tickers' positions"
}
# check if file exists; if not, end program
file_exists()
{
find "$1" 1>/dev/null 2>/dev/null
if [ "$?" -eq 1 ] # if the above find failed, ie if there is no such a file
then
echo "tradelog: $1: no such file"
exit 1
fi
}
# compare two dates; return: 1 if first date is newer, 2 if second date is newer, 0 if same
compare_date()
{
awk -v first="$1" -v second="$2" 'BEGIN{ if(first > second) print 1; else if(fist < second) print 2; else print 0 }'
}
### VARIABLES
DATETIME_AFTER="0000-00-00 00:00:00"
DATIME_BEFORE="9999-99-99 99:99:99"
TICKERS=""
WIDTH=""
CMD=""
LOG_LOADED=0 # 0 if not loaded, 1 if loaded
DATA=""
### PROCESS ARGUMENTS
while [ "$#" -gt 0 ] # while there are arguments left
do
case "$1" in
-h | --help)
print_help
exit 0
;;
-a) # if multiple -a are given, intersection is set (ie the newest date)
CMP=$(compare_date "$2" "$DATETIME_AFTER")
if [ "$CMP" -eq 1 ] # if date in argument is newer than current date
then
DATETIME_AFTER="$2"
fi
shift # shift -a argument
shift # shift DATETIME argument
;;
-b) # if multiple -b are given, intersection is set (ie the oldest date)
CMP=$(compare_date "$2" "$DATIME_BEFORE")
if [ "$CMP" -eq 2 ] # if date in argument is older than current date
then
DATIME_BEFORE="$2"
fi
shift
shift
;;
-t)
TICKERS="$TICKERS|$2"
shift
shift
;;
-w)
if [ "$WIDTH" ] # max one WIDTH allowed
then
echo "tradelog: WIDTH already set"
exit 1
fi
if ! [ "$2" -eq "$2" ] 2>/dev/null # WIDTH not a number
then
echo "tradelog: WIDTH must be a number"
exit 1
fi
if [ "$2" -lt 0 ] # WIDTH less than zero
then
echo "tradelog: WIDTH must be positive number"
exit 1
fi
WIDTH="$2"
shift
shift
;;
list-tick | profit | pos | last-price | hist-ord | graph-pos)
if [ "$CMD" ] # max one COMMAND allowed
then
echo "tradelog: COMMAND already set"
exit 1
fi
CMD="$1"
shift
;;
*.gz )
file_exists "$1"
DATA="${DATA}$(gzip -d -c "$1")" # load from decompressed .gz file and append to rest of loaded data
LOG_LOADED=1
shift
;;
*)
file_exists "$1"
DATA=$(echo "$DATA" | cat - "$1") # load from file and append to rest of loaded data
LOG_LOADED=1
shift
;;
esac
done
if [ "$LOG_LOADED" -eq 0 ] # if no file specified
then
DATA=$(cat -) # load from stdin
fi
### FILTERS
DATA=$(echo "$DATA" | awk -F \; -v datetime_after="$DATETIME_AFTER" '{ if($1 > datetime_after) print $0; }')
DATA=$(echo "$DATA" | awk -F \; -v datetime_before="$DATIME_BEFORE" '{ if($1 < datetime_before) print $0; }')
if [ -z "$TICKERS" ] # if no ticker specified
then
TICKERS=".*" # regex for all tickers
fi
DATA=$(echo "$DATA" | awk -F \; -v filter="^($TICKERS)$" '{ if($2 ~ filter) print $0; }') # filter tickers using regex
### COMMANDS
case "$CMD" in
list-tick) # get all tickers, sort them and print just unique
DATA=$(echo "$DATA" | awk -F \; '{ print $2; }' | sort | uniq)
;;
profit) # compute overall profit and print it
DATA=$(echo "$DATA" | awk -F \; \
' {
if($3 == "sell") sold += $4 * $6;
if($3 == "buy") bought += $4 * $6;
}
END {
printf("%.2f", sold - bought);
} ')
;;
pos) # sort dates, compute values of current tickers' positions and print for each ticker sorted using values
DATA=$(echo "$DATA" | sort -t \; -k1,1 | awk -F \; \
' {
if($3 == "buy") count[$2] += $6;
if($3 == "sell") count[$2] -= $6;
price[$2] = $4; # dates are sorted, so last price is always last for each ticker
}
END {
numlen = 0;
for(i in count)
{
pos[i] = sprintf("%.2f", count[i] * price[i]);
if(length(pos[i]) > numlen) numlen = length(pos[i]);
}
for(i in pos)
printf("%-10s: %*.2f\n", i, numlen, pos[i]);
} ' | sort -n -r -t : -k2,2)
;;
last-price) # sort dates, find last known tickers' prices and print for each ticker sorted
DATA=$(echo "$DATA" | sort -t \; -k1,1 | awk -F \; \
' {
price[$2] = sprintf("%.2f", $4); # dates are sorted, so last price is always last for each ticker
}
END {
numlen = 0;
for(i in price)
if(length(price[i]) > numlen) numlen = length(price[i]);
for(i in price)
printf("%-10s: %*.2f\n", i, numlen, price[i]);
} ' | sort)
;;
hist-ord) # compute number of tickers' transactions and show histogram for each ticker sorted
DATA=$(echo "$DATA" | awk -F \; -v width="$WIDTH" \
' {
count[$2]++;
}
END {
if(length(width) != 0) # only needed when WIDTH set
{
max = 0;
for(i in count)
if(count[i] > max) max = count[i];
}
for(i in count)
{
printf("%-10s:", i);
if(length(width) == 0) # WIDTH not set
len = count[i];
else # WIDTH set
len = int((count[i] / max) * width);
if(len != 0) # print space only if histogram follows
printf(" ");
for(j = 0; j < len; j++)
printf("#");
printf("\n");
}
} ' | sort)
;;
graph-pos) # sort dates, compute values of current tickers' positions and show graph for each ticker sorted
DATA=$(echo "$DATA" | sort -t \; -k1,1 | awk -F \; -v width="$WIDTH" \
' function abs(x)
{
return x < 0 ? -x : x;
}
{
if($3 == "buy") count[$2] += $6;
if($3 == "sell") count[$2] -= $6;
price[$2] = $4; # dates are sorted, so last price is always last for each ticker
}
END {
max = 0;
for(i in count)
{
pos[i] = count[i] * price[i];
if(length(width) != 0) # only needed when WIDTH set
if(abs(pos[i]) > max) max = abs(pos[i]);
}
for(i in count)
{
printf("%-10s:", i);
if(length(width) == 0) # WIDTH not set
len = int(abs(pos[i]) / 1000);
else # WIDTH set
len = int((abs(pos[i]) / max) * width);
if(len != 0) # print space only if graph follows
printf(" ");
for(j = 0; j < len; j++)
{
if(pos[i] > 0)
printf "#";
else
printf "!";
}
printf("\n");
}
} ' | sort)
;;
esac
### PRINT ALL DATA
echo "$DATA"
exit 0