Skip to content
This repository was archived by the owner on Feb 16, 2020. It is now read-only.

Commit 6e6bc77

Browse files
committed
archive stopped & errored gekkos
1 parent 4396b21 commit 6e6bc77

File tree

14 files changed

+125
-68
lines changed

14 files changed

+125
-68
lines changed

core/workers/pipeline/child.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,13 @@ process.on('message', function(m) {
5252
process.on('disconnect', function() {
5353
console.log('disconnect');
5454
process.exit(-1);
55-
})
55+
})
56+
57+
process
58+
.on('unhandledRejection', (message, p) => {
59+
process.send({type: 'error', message: message});
60+
})
61+
.on('uncaughtException', err => {
62+
process.send({type: 'error', error: err});
63+
process.exit(1);
64+
});

core/workers/pipeline/messageHandlers/backtestHandler.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ module.exports = done => {
55

66
return {
77
message: message => {
8+
if(message.type === 'error') {
9+
done(message.error);
10+
}
11+
812
if(message.backtest) {
913
done(null, message.backtest);
1014
}

core/workers/pipeline/messageHandlers/importerHandler.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ module.exports = cb => {
1111

1212
else if(message.type === 'error') {
1313
cb(message.error);
14-
console.error(message.error);
1514
}
1615

1716
else if(message.type === 'log')

core/workers/pipeline/messageHandlers/realtimeHandler.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ module.exports = cb => {
88

99
if(message.type === 'error') {
1010
cb(message.error);
11-
console.error(message.error);
1211
}
1312

1413
else

core/workers/pipeline/parent.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ module.exports = (mode, config, callback) => {
2525
if(m === 'done')
2626
return child.send({what: 'exit'});
2727

28-
if(m && m.type === 'error')
29-
return console.error(m.error);
30-
3128
handle.message(m);
3229
});
3330

sample-config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ config.trader = {
215215
secret: '',
216216
username: '', // your username, only required for specific exchanges.
217217
passphrase: '', // GDAX, requires a passphrase.
218-
orderUpdateDelay: 1, // Number of minutes to adjust unfilled order prices
219218
}
220219

221220
config.eventLogger = {

web/routes/baseConfig.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ config.childToParent = {
3535
enabled: false,
3636
}
3737

38-
config.trader = {
39-
orderUpdateDelay: 1 // Number of minutes to adjust unfilled order prices
40-
}
41-
4238
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4339
// CONFIGURING ADAPTER
4440
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

web/state/gekkoManager.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ const broadcast = require('./cache').get('broadcast');
66
const Logger = require('./logger');
77
const pipelineRunner = require('../../core/workers/pipeline/parent');
88
const reduceState = require('./reduceState.js');
9-
const now = () => moment().format('YYYY-MM-DD-HH-mm');
9+
const now = () => moment().format('YYYY-MM-DD HH:mm');
1010

1111
const GekkoManager = function() {
1212
this.gekkos = {};
1313
this.instances = {};
1414
this.loggers = {};
1515

16-
this.finishedGekkos = {};
16+
this.archivedGekkos = {};
1717
}
1818

1919
GekkoManager.prototype.add = function({mode, config}) {
@@ -36,8 +36,9 @@ GekkoManager.prototype.add = function({mode, config}) {
3636
logType = 'papertrader';
3737
}
3838

39+
const date = now().replace(' ', '-').replace(':', '-');
3940
const n = (Math.random() + '').slice(3);
40-
const id = `${now()}-${logType}-${n}`;
41+
const id = `${date}-${logType}-${n}`;
4142

4243
// make sure we catch events happening inside te gekko instance
4344
config.childToParent.enabled = true;
@@ -50,6 +51,8 @@ GekkoManager.prototype.add = function({mode, config}) {
5051
logType,
5152
active: true,
5253
stopped: false,
54+
errored: false,
55+
errorMessage: false,
5356
events: {
5457
initial: {},
5558
latest: {}
@@ -73,7 +76,7 @@ GekkoManager.prototype.add = function({mode, config}) {
7376
console.log(`${now()} Gekko ${id} started.`);
7477

7578
broadcast({
76-
type: 'new_gekko',
79+
type: 'gekko_new',
7780
id,
7881
state
7982
});
@@ -117,7 +120,7 @@ GekkoManager.prototype.handleFatalError = function(id, err) {
117120
return;
118121

119122
state.errored = true;
120-
state.active = false;
123+
state.errorMessage = err;
121124
console.error('RECEIVED ERROR IN GEKKO INSTANCE', id);
122125
console.error(err);
123126
broadcast({
@@ -126,7 +129,7 @@ GekkoManager.prototype.handleFatalError = function(id, err) {
126129
error: err
127130
});
128131

129-
this.delete(id);
132+
this.archive(id);
130133

131134
if(state.logType === 'watcher') {
132135
this.handleWatcherError(state, id);
@@ -142,7 +145,10 @@ GekkoManager.prototype.handleWatcherError = function(state, id) {
142145
console.log(`${now()} was unable to start.`);
143146
}
144147

145-
const latestCandleTime = state.events.latest.candle.start
148+
let latestCandleTime = moment.unix(0);
149+
if(state.events.latest && state.events.latest.candle) {
150+
latestCandleTime = state.events.latest.candle.start;
151+
}
146152
const leechers = _.values(this.gekkos)
147153
.filter(gekko => {
148154
if(gekko.type !== 'leech') {
@@ -157,12 +163,13 @@ GekkoManager.prototype.handleWatcherError = function(state, id) {
157163
if(leechers.length) {
158164
console.log(`${now()} ${leechers.length} leecher(s) were depending on this watcher.`);
159165
if(moment().diff(latestCandleTime, 'm') < 60) {
160-
console.log(`${now()} Watcher had recent data, starting a new one.`);
166+
console.log(`${now()} Watcher had recent data, starting a new one in a minute.`);
167+
// after a minute try to start a new one again..
161168
setTimeout(() => {
162169
const mode = 'realtime';
163170
const config = state.config;
164171
this.add({mode, config});
165-
})
172+
}, 1000 * 60);
166173
} else {
167174
console.log(`${now()} Watcher did not have recent data, killing its leechers.`);
168175
leechers.forEach(leecher => this.stop(leecher.id));
@@ -189,20 +196,25 @@ GekkoManager.prototype.stop = function(id) {
189196
id
190197
});
191198

199+
this.archive(id);
200+
192201
return true;
193202
}
194203

195-
GekkoManager.prototype.delete = function(id) {
196-
this.finishedGekkos[id] = this.gekkos[id];
204+
GekkoManager.prototype.archive = function(id) {
205+
this.archivedGekkos[id] = this.gekkos[id];
206+
this.archivedGekkos[id].stopped = true;
207+
this.archivedGekkos[id].active = false;
197208
delete this.gekkos[id];
209+
198210
broadcast({
199-
type: 'delete_gekko',
211+
type: 'gekko_archived',
200212
id
201213
});
202214
}
203215

204216
GekkoManager.prototype.list = function() {
205-
return this.gekkos;
217+
return { live: this.gekkos, archive: this.archivedGekkos };
206218
}
207219

208220
module.exports = GekkoManager;

web/vue/src/components/gekko/list.vue

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<template lang='pug'>
22
.contain.py2
3-
.text(v-html='text')
43
.hr
54
h3 Market watchers
65
.text(v-if='!watchers.length')
@@ -11,6 +10,7 @@
1110
th exchange
1211
th currency
1312
th asset
13+
th status
1414
th started at
1515
th last update
1616
th duration
@@ -19,6 +19,7 @@
1919
td {{ gekko.config.watch.exchange }}
2020
td {{ gekko.config.watch.currency }}
2121
td {{ gekko.config.watch.asset }}
22+
td {{ status(gekko) }}
2223
td
2324
template(v-if='gekko.events.initial.candle') {{ fmt(gekko.events.initial.candle.start) }}
2425
td
@@ -34,7 +35,7 @@
3435
th exchange
3536
th currency
3637
th asset
37-
th last update
38+
th status
3839
th duration
3940
th strategy
4041
th PnL
@@ -45,8 +46,7 @@
4546
td {{ gekko.config.watch.exchange }}
4647
td {{ gekko.config.watch.currency }}
4748
td {{ gekko.config.watch.asset }}
48-
td
49-
template(v-if='gekko.events.latest.candle') {{ fmt(gekko.events.latest.candle.start) }}
49+
td {{ status(gekko) }}
5050
td
5151
template(v-if='gekko.events.initial.candle && gekko.events.latest.candle') {{ timespan(gekko.events.latest.candle.start, gekko.events.initial.candle.start) }}
5252
td {{ gekko.config.tradingAdvisor.method }}
@@ -63,25 +63,10 @@
6363
</template>
6464

6565
<script>
66-
67-
import marked from '../../tools/marked'
6866
// global moment
6967
// global humanizeDuration
7068
71-
const text = marked(`
72-
73-
## Live Gekko
74-
75-
Run your strategy against the live market!
76-
77-
`);
78-
7969
export default {
80-
data: () => {
81-
return {
82-
text
83-
}
84-
},
8570
created: function() {
8671
this.timer = setInterval(() => {
8772
this.now = moment();
@@ -92,26 +77,27 @@ export default {
9277
},
9378
data: () => {
9479
return {
95-
text,
9680
timer: false,
9781
now: moment()
9882
}
9983
},
10084
computed: {
10185
stratrunners: function() {
10286
return _.values(this.$store.state.gekkos)
103-
.filter(g => {
104-
if(g.logType === 'papertrader')
105-
return true;
87+
.concat(_.values(this.$store.state.archivedGekkos))
88+
.filter(g => {
89+
if(g.logType === 'papertrader')
90+
return true;
10691
107-
if(g.logType === 'tradebot')
108-
return true;
92+
if(g.logType === 'tradebot')
93+
return true;
10994
110-
return false;
111-
});
95+
return false;
96+
})
11297
},
11398
watchers: function() {
11499
return _.values(this.$store.state.gekkos)
100+
.concat(_.values(this.$store.state.archivedGekkos))
115101
.filter(g => g.logType === 'watcher')
116102
}
117103
},
@@ -122,6 +108,16 @@ export default {
122108
round: n => (+n).toFixed(3),
123109
timespan: function(a, b) {
124110
return this.humanizeDuration(this.moment(a).diff(this.moment(b)))
111+
},
112+
status: state => {
113+
if(state.errored)
114+
return 'errored';
115+
if(state.stopped)
116+
return 'stopped';
117+
if(state.active)
118+
return 'running';
119+
120+
console.log('unknown state:', state);
125121
}
126122
}
127123
}

web/vue/src/components/gekko/singleGekko.vue

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
p Gekko doesn't know what gekko this is...
66
div(v-if='data')
77
h2.contain Gekko {{ type }}
8+
div(v-if='isArchived', class='contain brdr--mid-gray p1 bg--orange')
9+
| This is an archived Gekko, it is currently not running anymore.
10+
div(v-if='data.errorMessage', class='contain brdr--mid-gray p1 bg--orange')
11+
| This is Gekko crashed with the following error: {{ data.errorMessage }}
812
.grd.contain
913
.grd-row
1014
.grd-row-col-3-6
@@ -57,7 +61,8 @@
5761
h3 Profit report
5862
template(v-if='!report')
5963
p
60-
em Waiting for at least one trade..
64+
em(v-if='isArchived') This Gekko never executed a trade..
65+
em(v-if='!isArchived') Waiting for at least one trade..
6166
template(v-if='report')
6267
.grd-row
6368
.grd-row-col-3-6 Start balance
@@ -74,7 +79,7 @@
7479
.grd-row
7580
.grd-row-col-3-6 Alpha
7681
.grd-row-col-3-6 {{ round(report.alpha) }} {{ config.watch.currency }}
77-
p(v-if='isStratrunner && !watcher') WARNING: stale gekko, not attached to a watcher, please report
82+
p(v-if='isStratrunner && !watcher && !isArchived') WARNING: stale gekko, not attached to a watcher, please report
7883
a(href='https://github.com/askmike/gekko/issues') here
7984
| .
8085
p(v-if='isStratrunner && watcher')
@@ -125,13 +130,16 @@ export default {
125130
gekkos: function() {
126131
return this.$store.state.gekkos;
127132
},
133+
archivedGekkos: function() {
134+
return this.$store.state.archivedGekkos;
135+
},
128136
data: function() {
129137
if(!this.gekkos)
130138
return false;
131139
if(_.has(this.gekkos, this.id))
132140
return this.gekkos[this.id];
133-
if(_.has(this.finishedGekkos, this.id))
134-
return this.finishedGekkos[this.id];
141+
if(_.has(this.archivedGekkos, this.id))
142+
return this.archivedGekkos[this.id];
135143
136144
return false;
137145
},
@@ -159,6 +167,9 @@ export default {
159167
isStratrunner: function() {
160168
return this.type !== 'watcher';
161169
},
170+
isArchived: function() {
171+
return this.stopped;
172+
},
162173
chartData: function() {
163174
return {
164175
candles: this.candles,
@@ -245,10 +256,13 @@ export default {
245256
candleSize
246257
};
247258
259+
// We timeout because of 2 reasons:
260+
// - In case we get a batch of candles we only fetch once
261+
// - This way we give the db (mostly sqlite) some time to write
262+
// the result before we query it.
248263
setTimeout(() => {
249264
post('getCandles', config, (err, res) => {
250265
this.candleFetch = 'fetched';
251-
// todo
252266
if(!res || res.error || !_.isArray(res))
253267
return console.log(res);
254268

0 commit comments

Comments
 (0)