-
Notifications
You must be signed in to change notification settings - Fork 1
/
analyze.lua
366 lines (328 loc) · 11.1 KB
/
analyze.lua
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
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
local torch = require 'torch'
package.path = './?.lua;' .. package.path
local Env = dofile 'env.lua'
local Data = dofile 'data.lua'
local Syntax = dofile 'syntax.lua'
local Account = dofile 'account.lua'
local Processor = dofile 'processor.lua'
local Species = dofile 'species.lua'
local Prototypes = {}
function Prototypes:load()
local index = assert( Species.getIndex() )
print('Index has '..tostring(#index)..' records')
index:close()
self.weight_sum = 0
self.long_weight_sum = 0
self.short_weight_sum = 0
for i, info in ipairs(index) do
local specie, name
io.write('Loading '..tostring(info.name)..'...')
if (type(info.annual_rate) == 'number') and (info.annual_rate > 0)
--and (type(info.profit_factor) == 'number') and (info.profit_factor >= 1.5)
and (i <= 50) then
local entity = Syntax:entity(info.best_code)
if entity.sequence then
entity.weight = (info.profit_factor or 1)^3
self.weight_sum = self.weight_sum + entity.weight
if (info.signal_pos or 0) > 0 then
self.long_weight_sum = self.long_weight_sum + entity.weight
end
if (info.signal_neg or 0) > 0 then
self.short_weight_sum = self.short_weight_sum + entity.weight
end
table.insert(self, entity)
print('Yes')
else
print('Err')
end
else
print('Neg')
end
end -- for files
if #self <= 0 then return nil, 'Failed to load any file!' end
for _, entity in ipairs(self) do
entity.weight = (entity.weight / self.weight_sum)
end
return self
end -- function Prototypes:load
function Prototypes:tradeSeries(series, trading_amount)
trading_amount = trading_amount or #self
local n = series.ncandles
local candles = series.candles
local account = Account.init { position = 0 }
local states = {}
local last_day
-- Execute prototypes and get signal vectors
local vectors = {}
for p, entity in ipairs(self) do
local stack = {}
local stat = Processor:execute(entity.sequence, series, stack)
local x = stack[#stack]
if stat and x and torch.isTensor(x) then
x = torch.sign(x)
else
x = torch.zeros(n)
end -- if stat
if (x:nElement() ~= n) then
x = series:expand(x, candles.pc)
assert(x:nElement() == n, 'Prototypes:tradeSeries: Failed to expand vectors!')
end
vectors[p] = x
states[p] = { position = 0 }
end -- for Prototypes
-- Cycle through candles
for i = 1, n do
local tc = candles.tc[i]
local t = os.date('!*t', tc)
--if last_day and (last_day ~= t.yday) then
if (t.hour >= 20) and (t.min >= 49) then
-- Reset states at the end of a day
for p, _ in ipairs(self) do
local state = states[p]
state.position = 0
end
-- Reset position
if (account.position ~= 0) then
account:closePosition(candles.pc[i-1], candles.tc[i-1])
end
elseif (t.hour >= 07) and (t.min >= 10) then
-- Construct united signal
local desired_position = 0
for p, entity in ipairs(self) do
-- Get prototype signal
local state = states[p]
local signal = vectors[p][i]
signal = (signal == 0) and 0 or (signal > 0) and 1 or -1
-- Calculate prototype position based on signal
if (signal ~= state.position) then
state.position = signal
end
desired_position = desired_position + state.position * (entity.weight or 1)
end -- for Prototypes
-- Apply trading amount
desired_position = math.floor(trading_amount*desired_position + 0.5)
-- Update position at the end of a candle
if (account.position ~= desired_position) then
account:trade(desired_position - account.position, candles.pc[i], tc)
end
end
last_day = t.yday
end -- for candles
-- Construct report
return account
end -- function Prototypes:tradeSeries
function Prototypes:tradeSeries2(series, trading_amount)
trading_amount = trading_amount or #self
local n = series.nframes
local candles = series.frames
local account = Account.init { position = 0 }
local states = {}
-- Execute prototypes and get signal vectors
local vectors = {}
for p, entity in ipairs(self) do
local stack = {}
local stat = Processor:execute(entity.sequence, series, stack)
local x = stack[#stack]
if stat and x and torch.isTensor(x) then
x = torch.sign(x)
else
x = torch.zeros(n)
end -- if stat
if (x:nElement() ~= n) then
x = series:expand(x, candles.pc)
assert(x:nElement() == n, 'Prototypes:tradeSeries: Failed to expand vectors!')
end
vectors[p] = x
states[p] = { position = 0 }
end -- for Prototypes
-- Cycle through candles
for i = 1, n do
local tc = candles.tc[i]
-- Construct united signal
local desired_position = 0
for p, entity in ipairs(self) do
-- Get prototype signal
local state = states[p]
local signal = vectors[p][i]
signal = (signal > 0) and 1 or (signal < 0) and -1 or 0
-- Calculate prototype position based on signal
if (signal ~= state.position) then
state.position = signal
state.enter_date = tc
end
desired_position = desired_position + state.position * (entity.weight or 1)
end -- for Prototypes
-- Apply trading amount
desired_position = math.floor(trading_amount*desired_position + 0.5)
-- Update position at the end of a candle
if (account.position ~= desired_position) then
account:trade(desired_position - account.position, candles.pc[i], tc)
end
end -- for candles
-- Construct report
return account
end -- function Prototypes:tradeSeries2
function Prototypes:getSimilarityMatrix()
local n = #self
local M = torch.zeros(n, n)
for i, prototypeA in ipairs(self) do
for j = i, #self do
if i == j then
M[i][j] = 1
else
local prototypeB = self[j]
local similarity = Syntax:similarity(prototypeA.mishmash, prototypeB.mishmash)
M[i][j], M[j][i] = similarity, similarity
end -- if i == j
end -- for prototypes
end -- for prototypes
return M
end -- function Prototypes:getSimilarityMatrix
local function main()
local work_dir = arg[1]
if work_dir then
assert( lfs.chdir(work_dir) )
print('Changed dir to '..work_dir)
end
local robot = dofile 'config.lua'
assert(Dataset_File and Iterations_In_Epoch and robot,
'Invalid config file!')
-- Initialize Torch
math.randomseed( os.time() )
--torch.manualSeed(1)
torch.setdefaulttensortype('torch.FloatTensor')
torch.setnumthreads(2)
print('Loading Dataset...')
Dataset = Env.universalLoad(Dataset_File, 'binary')
assert(Dataset, 'Failed to load Dataset from '..tostring(Dataset_File))
print('Loaded Dataset from '..tostring(Dataset_File))
Env.printInfo('Dataset', Dataset)
Data.addExpand(Dataset)
-- Load profitable species
Prototypes:load()
if (#Prototypes <= 0) then
error('Failed to load any profitable algorithms!')
end
print('Loaded '..tostring(#Prototypes)..' prototypes')
local result = {}
for s, series in ipairs(Dataset) do
local n = series.ncandles
local candles = series.candles
io.write('\rProcessing '..tostring(s)..'/'..tostring(#Dataset))
io.flush()
local account = Prototypes:tradeSeries(series, robot.trading_amount)
if account and account.position then
account:closePosition(candles.pc[n], candles.tc[n])
-- Construct report
result[s] = account:makeReport(candles.to[1], candles.tc[n])
end
end
print('')
local avg_rate = 0
local NA = 'N/A'
print('##\t#trades\tRate%\tDDown%\tPF\tRF')
for i, report in ipairs(result) do
print(string.format('%02d', i)..'\t'..
(report.n_trades and string.format('%d', report.n_trades) or NA)..'\t'..
(report.annual_rate and string.format('%.2f', 100*report.annual_rate) or NA)..'\t'..
(report.max_drawdown_percent and string.format('%.2f', 100*report.max_drawdown_percent) or NA)..'\t'..
(report.profit_factor and string.format('%.2f', report.profit_factor) or NA)..'\t'..
(report.recovery_factor and string.format('%.2f', report.recovery_factor) or NA))
--Env.printInfo('Report '..tostring(i), report)
avg_rate = avg_rate + (report.annual_rate or 0)
end
avg_rate = avg_rate / #result
print('Average rate: '..string.format('%.2f', 100*avg_rate))
if false then
local M = Prototypes:getSimilarityMatrix()
print(M)
local result = {}
local processed = {}
local i = 1
while true do
local a = Prototypes[i]
table.insert(result, a)
processed[a] = true
local max_similarity, next_i
for j = 1, #Prototypes do
local b = Prototypes[j]
if (not processed[b]) and (i ~= j) then
if (not max_similarity) or (M[i][j] > max_similarity) then
max_similarity = M[i][j]
next_i = j
end
end
end -- for
if not next_i then break end
i = next_i
end
end
end -- function main
main()
--local function update()
-- local work_dir = arg[1] or '.'
-- if (work_dir ~= '.') then
-- assert( lfs.chdir(work_dir) )
-- print('Changed dir to', work_dir)
-- end
-- require 'config'
-- assert(Dataset_File, 'Invalid config file!')
-- -- Initialize Torch
-- math.randomseed( os.time() )
-- --torch.manualSeed(1)
-- torch.setdefaulttensortype('torch.FloatTensor')
-- torch.setnumthreads(4)
-- print('Loading Dataset...')
-- Dataset = Env.universalLoad(Dataset_File, 'binary')
-- assert(Dataset, 'Failed to load Dataset from '..tostring(Dataset_File))
-- print('Loaded Dataset from '..tostring(Dataset_File))
-- Env.printInfo('Dataset', Dataset)
-- Data.addExpand(Dataset)
-- for _, specie in ipairs(Env) do
-- print('Exporting', tostring(specie.name))
-- assert( Species.saveSpecie(specie) )
-- local s = assert( Species.openSpecie(specie.name) )
-- s:export()
-- s:close()
-- end
-- print('Rebuilding index')
-- local index = assert( Species.getIndex() )
-- index:sort()
-- print('Index has:')
-- for k, info in pairs(index) do
-- print(k,'=',info.name)
-- end
-- index:save()
-- index:close()
--end -- function update
--update()
--local function update()
-- local work_dir = arg[1] or '.'
-- if (work_dir ~= '.') then
-- assert( lfs.chdir(work_dir) )
-- print('Changed dir to', work_dir)
-- end
-- require 'config'
-- assert(Dataset_File, 'Invalid config file!')
-- -- Initialize Torch
-- math.randomseed( os.time() )
-- --torch.manualSeed(1)
-- torch.setdefaulttensortype('torch.FloatTensor')
-- torch.setnumthreads(4)
-- -- Aquire and lock index
-- print('Aquiring index...')
-- local Index = assert( Species.getIndex() )
-- print('Index has '..tostring(#Index)..' records')
-- local specie = Species.importSpecieFromFile('hemera.export.dat')
-- local info = assert( Species.getSpecieInfo(specie) )
-- Index:update(info.name, info)
-- -- Save specie
-- print('Saving specie '..tostring(specie.name))
-- assert( specie:save() )
-- specie:export()
-- specie:close()
-- print('Saving index')
-- assert( Index:save() )
-- Index:close()
--end -- function update
--update()