Skip to content

Commit

Permalink
Merge pull request #9 from gobeli/feature/ccxt
Browse files Browse the repository at this point in the history
Feature/ccxt
  • Loading branch information
Etienne authored Jan 18, 2018
2 parents f280031 + af4ae9b commit ccadb61
Show file tree
Hide file tree
Showing 15 changed files with 327 additions and 226 deletions.
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ script:
branches:
only:
- master

deploy:
provider: releases
api_key: $GH_TOKEN
file:
- build/pump-and-dump-0.2.0.dmg
- build/pump-and-dump-0.2.0-x86_64.AppImage
skip_cleanup: true
on:
tags: true
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
# pump-and-dump [![Build status](https://ci.appveyor.com/api/projects/status/7o7kpe26ejv5d09j?svg=true)](https://ci.appveyor.com/project/gobeli/pump-and-dump) #
# pump-and-dump #
[![Build status](https://ci.appveyor.com/api/projects/status/7o7kpe26ejv5d09j?svg=true)](https://ci.appveyor.com/project/gobeli/pump-and-dump)[![Build Status](https://travis-ci.org/gobeli/pump-and-dump.svg?branch=master)](https://travis-ci.org/gobeli/pump-and-dump)

A pump and dump application for cryptocurrencies using the bittrex API
A pump and dump application for cryptocurrencies using [ccxt](https://github.com/ccxt/ccxt)

Setup generated with [electron-vue](https://github.com/SimulatedGREG/electron-vue)

## [Releases](https://github.com/gobeli/pump-and-dump/releases) ##

## Tips
- Some exchanges have timeouts / request limits, to prevent them adjust the polling timeout via the textbox so stuff doesn't break ;)
- I have only tested some exchanges, which means I can't guarantee that it will work on every exchange [ccxt](https://github.com/ccxt/ccxt) provides. If yours does not work open an Issue or even better a PR with a fix.

## Screenshots ##
![alt text](https://raw.githubusercontent.com/gobeli/pump-and-dump/master/static/screen1.png)

![alt text](https://raw.githubusercontent.com/gobeli/pump-and-dump/master/static/screen2.png)

## License
Released under the MIT license. See [LICENSE](LICENSE) for more info.

_Use at your own risk_
46 changes: 42 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
"pack": "npm run pack:main && npm run pack:renderer",
"pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js",
"pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js",
"postinstall": ""
"postinstall": "",
"release": "build"
},
"build": {
"productName": "pump-and-dump",
"appId": "org.simulatedgreg.electron-vue",
"appId": "org.gobeli.pump-and-dump",
"directories": {
"output": "build"
},
Expand Down Expand Up @@ -53,6 +54,7 @@
"dependencies": {
"ajv": "^5.3.0",
"axios": "^0.16.2",
"ccxt": "^1.10.643",
"chart.js": "^2.7.1",
"element-ui": "^2.0.4",
"node-sass": "^4.6.1",
Expand Down
3 changes: 2 additions & 1 deletion src/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
</script>
<% } %>
<style> ::selection {
background:rgba(255, 255, 125, 0.99)
background:rgba(255, 255, 125, 0.99);
color:#032764;
overflow-x: hidden;
}</style>
</head>
<body style="background-color: #F5F5F5">
Expand Down
55 changes: 55 additions & 0 deletions src/renderer/components/Chart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<vue-chart
:rows="$store.state.marketData.map(x => [null, x.last, x.buy, x.sell])"
:columns="[{ type: 'string', label: '' },{ type: 'number', label: 'Last' }, { type: 'number', label: 'Buy' }, { type: 'number', label: 'Sell' }]"
:options="chartOptions"
></vue-chart>
</template>

<script>
importhandleError } from '../helper';
export default {
name: 'pnd-chart',
props: ['strategy', 'pollingTimeout', 'market'],
data: () => ({
marketData: [],
tickerInterval: null,
chartOptions: {
annotations: {
duration: 1000,
easing: 'out',
},
hAxis: {
title: 'time',
},
vAxis: {
title: 'price',
},
},
}),
created() {
this.createTicker(this.pollingTimeout);
},
watch: {
pollingTimeout(newVal, oldVal) {
this.createTicker(newVal);
}
},
methods: {
createTicker(pollingTimeout) {
clearInterval(this.tickerInterval);
this.tickerInterval = setInterval(this.updateTicker.bind(this), pollingTimeout);
this.updateTicker();
},
updateTicker() {
this.$store.state.exchange.fetchTicker(this.market).catch(handleError(this))
.then(tick =>
this.$store.commit('ADD_MARKETDATA', {last: tick.last,
buy: this.$store.state.running ? this.$store.state.settings.buy : null,
sell: this.$store.state.running ? this.$store.state.settings.sell : null
})
);
}
}
}
</script>
73 changes: 32 additions & 41 deletions src/renderer/components/ExecuteModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@
:visible.sync="open"
size="tiny"
:before-close="() => $emit('close-modal')">
<h3>Trade {{marketSummary.MarketName}}</h3>
<p>Buy: <strong>{{quantity}} {{market}}</strong> at <strong>{{bid}}</strong> bid</p>
<p>Sell at <strong>{{ask}}</strong> ask</p>
<h3>Trade {{market}} ({{lastPrice}})</h3>
<p>Buy: <strong>{{quantity}} {{market}}</strong> at <strong>{{bid}}</strong></p>
<p>Sell at <strong>{{ask}}</strong></p>
<el-button type="primary" @click="submit()">Ok</el-button>
</el-dialog>

</template>
<script>
import { handleResponse } from '../helper';
<script>
import { mapGetters } from 'vuex';
import { handleError } from '../helper';
export default {
name: 'execute-modal',
name: 'pnd-execute-modal',
props: ['open', 'strategy', 'market'],
data: () => ({
marketSummary: {}
}),
watch: {
open() {
this.update();
Expand All @@ -32,63 +31,55 @@
}
},
computed: {
...mapGetters([
'lastPrice',
]),
rateBuy() {
return 1 + (this.strategy.buyAt / 100);
},
rateSell() {
return 1 + (this.strategy.sellAt / 100);
},
bid() {
return this.marketSummary.Bid * this.rateBuy;
return this.lastPrice && this.lastPrice * this.rateBuy;
},
ask() {
return this.marketSummary.Ask * this.rateSell;
return this.lastPrice && this.lastPrice * this.rateSell;
},
quantity() {
if (this.marketSummary && this.strategy) {
if (this.lastPrice && this.strategy) {
return this.strategy.volume / this.bid;
}
},
},
methods: {
update() {
if (!this.market || this.market.length < 3) {
if (!this.market || this.market.length < 3) {
return;
}
this.$bittrex.getmarketsummary({market: `BTC-${this.market}`},
(data, err) => this.marketSummary = handleResponse(data, err, this)[0] || {});
},
buy(cb) {
this.$bittrex.buylimit({ market: `BTC-${this.market}`, quantity: this.quantity, rate: this.bid }, (data, err) => {
const res = handleResponse(data, err, this);
if (res.uuid) {
submit() {
let buyOrder;
this.$store.state.exchange.createLimitBuyOrder(this.market, this.quantity, this.bid)
.then(b => {
this.$message({
message: 'Buy-Order successfull',
message: 'Buy-Order placed successfully',
type: 'success',
});
cb();
}
});
},
sell(cb) {
this.$bittrex.selllimit({ market: `BTC-${this.market}`, quantity: this.quantity, rate: this.ask }, (data, err) => {
const res = handleResponse(data, err, this);
if (res.uuid) {
buyOrder = b;
})
.then(() => this.$store.state.exchange.createLimitSellOrder(this.market, this.quantity, this.ask))
.then(s => {
this.$message({
message: 'Sell-Order successfull',
message: 'Sell-Order placed successfully',
type: 'success',
});
cb();
}
});
},
submit() {
this.buy(() => this.sell(() => {
this.$bus.$emit('update');
this.$emit('close-modal');
this.$store.commit('SET_RUNNING', { running: true, settings: { buy: this.bid, sell: this.ask, quantity: this.quantity } });
}));
this.$bus.$emit('update');
this.$emit('close-modal');
this.$store.commit('SET_RUNNING', { running: true, settings: { buy: this.bid, sell: this.ask, quantity: this.quantity, buyOrder, sellOrder: s } });
})
.catch(handleError(this));
}
}
}
</script>
</script>
18 changes: 15 additions & 3 deletions src/renderer/components/Login.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
<template>
<el-form>
<el-form-item label="Exchange">
<el-select style="width: 100%" v-model="apiModel.exchange" placeholder="Exchange" filterable>
<el-option
v-for="e in $ccxt.exchanges"
:key="e"
:label="e"
:value="e">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="API Key">
<el-input style="width: 100%" v-model="apiModel.key"></el-input>
</el-form-item>
Expand All @@ -10,21 +20,23 @@
</el-form>
</template>
<script>
import { setApiKey, setApiSecret } from '../helper';
import { setApiKey, setApiSecret, setExchange } from '../helper';
export default {
data: () => ({
apiModel: {
key: '',
secret: '',
},
exchange: ''
}
}),
methods: {
submit() {
setApiKey(this.apiModel.key);
setApiSecret(this.apiModel.secret);
this.$router.go('/app');
setExchange(this.apiModel.exchange);
this.$router.push('/app');
},
}
}
Expand Down
Loading

0 comments on commit ccadb61

Please sign in to comment.