Skip to content

Commit

Permalink
manage API keys in the UI!
Browse files Browse the repository at this point in the history
  • Loading branch information
askmike committed Jul 26, 2017
1 parent baa8b64 commit 9654d6a
Show file tree
Hide file tree
Showing 16 changed files with 254 additions and 31 deletions.
4 changes: 2 additions & 2 deletions core/exchangeChecker.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ Checker.prototype.cantTrade = function(conf) {
var exchange = this.getExchangeCapabilities(slug);
var name = exchange.name;

if('tradeError' in exchange)
return 'At this moment Gekko can\'t trade at ' + name + ', find out more info here:\n\n' + exchange.tradeError;
if(!exchange.tradable)
return 'At this moment Gekko can\'t trade at ' + name + '.';

if(conf.key === 'your-key')
return '"your-key" is not a valid API key';
Expand Down
4 changes: 2 additions & 2 deletions docs/extending/add_an_exchange.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ Each exchange *must* provide a `getCapabilities()` static method that returns an
- `tid`: When Gekko needs to pass in a trade id to act as a starting point in time.
- `false`: When the exchange does not support to give back historical data at all.
- `fetchTimespan`: if the timespan between first and last trade per fetch is fixed, set it here in minutes.
- `monitorError`: if Gekko is currently not able to monitor this exchange, please set it to an URL explaining the problem.
- `tradeError`: If gekko is currently not able to trade at this exchange, please set it to an URL explaining the problem.
- `tradable`: if gekko supports automatic trading on this exchange.
- `requires`: if gekko supports automatic trading, this is an array of required api credentials gekko needs to pass into the constructor.

Below is a real-case example how `bistamp` exchange provides its `getCapabilities()` method:

Expand Down
3 changes: 2 additions & 1 deletion exchanges/btce.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ Trader.getCapabilities = function () {
],
requires: ['key', 'secret'],
providesHistory: false,
tid: 'tid'
tid: 'tid',
tradable: true
};
}

Expand Down
3 changes: 2 additions & 1 deletion exchanges/gdax.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ Trader.getCapabilities = function () {
requires: ['key', 'secret', 'passphrase'],
providesHistory: 'date',
providesFullHistory: true,
tid: 'tid'
tid: 'tid',
tradable: true
};
}

Expand Down
3 changes: 2 additions & 1 deletion exchanges/kraken.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,8 @@ Trader.getCapabilities = function () {
],
requires: ['key', 'secret'],
providesHistory: false,
tid: 'date'
tid: 'date',
tradable: true
};
}

Expand Down
2 changes: 2 additions & 0 deletions exchanges/mtgox.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// HERE FOR HISTORICAL PURPOSES

var MtGoxClient = require("mtgox-apiv2");
var _ = require('lodash');
var moment = require('moment');
Expand Down
3 changes: 2 additions & 1 deletion exchanges/poloniex.js
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@ Trader.getCapabilities = function () {
requires: ['key', 'secret'],
tid: 'tid',
providesHistory: 'date',
providesFullHistory: true
providesFullHistory: true,
tradable: true
};
}

Expand Down
15 changes: 14 additions & 1 deletion web/apiKeyManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,20 @@ module.exports = {
exchanges: _.keys(apiKeys)
});
},
remove: exchange => {
if(!apiKeys[exchange])
return;

// retrieve api keys, this cannot touch the frontend
delete apiKeys[exchange];
fs.writeFileSync(apiKeysFile, prefix + JSON.stringify(apiKeys));

broadcast({
type: 'apiKeys',
exchanges: _.keys(apiKeys)
});
},

// retrieve api keys
// this cannot touch the frontend for security reaons.
_getApiKeyPair: key => apiKeys[key]
}
13 changes: 12 additions & 1 deletion web/routes/apiKeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ module.exports = {

manager.add(content.exchange, content.values);

this.body = 'ok';
this.body = {
status: 'ok'
};
},
remove: function *() {
const exchange = this.request.body.exchange;

manager.remove(exchange);

this.body = {
status: 'ok'
};
}
}
2 changes: 1 addition & 1 deletion web/routes/startGekko.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const base = require('./baseConfig');
module.exports = function *() {
const mode = this.request.body.mode;

let config = {}
let config = {};

_.merge(config, base, this.request.body);

Expand Down
93 changes: 93 additions & 0 deletions web/vue/src/components/config/apiConfigBuilder.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<template lang='jade'>
.grd.contain
h3 Add an API key
p Make sure that the API key has the permissions to create and cancel orders and view balances.
.grd-row
.grd-row-col-3-6.mx1
h3 Exchange
exchange-picker.contain(v-on:exchange='updateExchange', only-tradable='true')
.grd-row-col-3-6.mx1
h3 Credentials
template(v-for='cred in requires')
label {{ cred }}
input(v-model='credentials[cred]')
.txt--center
a.w100--s.my1.btn--blue(href='#', v-on:click.prevent='upload') Add
</template>

<script>
import exchangePicker from '../global/configbuilder/exchangepicker.vue'
import _ from 'lodash'
import { post } from '../../tools/ajax';
export default {
data: () => {
return {
exchange: false,
credentials: {}
}
},
components: {
exchangePicker
},
computed: {
exchanges: function() {
return this.$store.state.exchanges;
},
requires: function() {
if(!this.exchanges)
return [];
if(!this.exchange)
return [];
return this.exchanges[this.exchange].requires;
},
config: function() {
let config = {
exchange: this.exchange,
values: this.credentials
};
return config;
}
},
watch: {
credentials: function() {
this.emitConfig();
}
},
methods: {
updateExchange: function(exchange) {
this.credentials = {};
this.exchange = exchange;
this.emitConfig();
},
emitConfig: function() {
this.$emit('config', this.config);
},
upload: function() {
let exchange = this.config.exchange;
if(
this.exchanges &&
this.exchanges[exchange] &&
!confirm(`You already have API keys for ${exchange} defined, want to overwrite them?`)
)
return;
post('addApiKey', this.config, (error, response) => {
if(error)
return alert(error);
this.credentials = {};
});
}
}
}
</script>

<style>
</style>
21 changes: 17 additions & 4 deletions web/vue/src/components/config/config.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,48 @@
div.contain
h2 Config
.hr
h3 API keys
h3 Available API keys
p(v-if='!apiKeySets.length')
em You don't have any API keys yet.
ul
li(v-for='set in apiKeySets')
li(v-for='exchange in apiKeySets') {{ exchange }}
a(href='#', v-if='!addApiToggle', v-on:click.prevent='openAddApi') add an API key
template(v-if='addApiToggle')
p a
.hr
apiConfigBuilder
.hr

</template>

<script>
import apiConfigBuilder from './apiConfigBuilder.vue';
export default {
components: {
apiConfigBuilder
},
data: () => {
return {
addApiToggle: false
addApiToggle: false,
}
},
methods: {
openAddApi: function() {
this.addApiToggle = true;
},
removeApiKey: function(exchange) {
}
},
computed: {
apiKeySets: function() {
return this.$store.state.apiKeys
}
},
watch: {
apiKeySets: function() {
this.addApiToggle = false;
}
}
}
</script>
3 changes: 2 additions & 1 deletion web/vue/src/components/data/import/importConfigBuilder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.grd-row
.grd-row-col-3-6.mx1
h3 Market
market-picker.contain(v-on:market='updateMarketConfig')
market-picker.contain(v-on:market='updateMarketConfig', only-importable='true')
.grd-row-col-3-6.mx1
range-creator(v-on:range='updateRange')
</template>
Expand All @@ -27,6 +27,7 @@ export default {
},
computed: {
config: function() {
let config = {};
Object.assign(
config,
Expand Down
65 changes: 65 additions & 0 deletions web/vue/src/components/global/configbuilder/exchangepicker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template lang='jade'>
div
.mx1
label(for='exchange').wrapper Exchange:
.custom-select.button
select(v-model='exchange')
option(v-for='(market, e) in exchanges') {{ e }}
</template>

<script>
import _ from 'lodash'
import rangePicker from './rangepicker.vue'
import rangeCreator from './rangecreator.vue'
import { get } from '../../../tools/ajax'
export default {
props: ['onlyTradable', 'onlyImportable'],
data: () => {
return {
exchange: 'poloniex',
};
},
created: function() {
this.emitExchange();
},
computed: {
exchanges: function() {
let exchanges = Object.assign({}, this.$store.state.exchanges);
if(_.isEmpty(exchanges))
return false;
if(this.onlyTradable) {
_.each(exchanges, (e, name) => {
if(!e.tradable)
delete exchanges[name];
});
}
if(this.onlyImportable) {
_.each(exchanges, (e, name) => {
if(!e.importable)
delete exchanges[name];
});
}
return exchanges;
}
},
watch: {
exchanges: function() { this.emitExchange() },
exchange: function() { this.emitExchange() }
},
methods: {
emitExchange: function() {
this.$emit('exchange', this.exchange);
}
}
}
</script>
</style>
Loading

0 comments on commit 9654d6a

Please sign in to comment.