Skip to content

Commit

Permalink
v0.7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksei Lebedev committed Mar 12, 2020
0 parents commit 6d54540
Show file tree
Hide file tree
Showing 29 changed files with 2,831 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Install EditorConfig Plugin on your IDE for one coding style
# EditorConfig is awesome: http://EditorConfig.org

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
tab_width = 4
[*.md]
max_line_length = off
trim_trailing_whitespace = false
44 changes: 44 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module.exports = {
"parserOptions": {
"ecmaVersion": 8,
"sourceType": "module"
},
"rules": {
quotes: ["error", "single"],
"semi": "warn", // обязательно ;
"semi-spacing": ["error", {"before": false, "after": true}],
"indent": ["error", "tab"],
"space-infix-ops": "error",// отступы вокруг + - * / = и тд
"eqeqeq": "error", // обязательно === и !== (нельзя == и !=)
// "no-eq-null": "error", // обязательно === и !== (нельзя == и !=) но тоько в отношении null
"curly": "error", // проверка шаблонов `${name}`
// "space-before-function-paren": [ // отступ до и после function
// "error", {
// "anonymous": "always",
// "named": "always",
// "asyncArrow": "ignore"
// }
// ],
"key-spacing": ["error", { "mode": "strict" }], // оформление обЪекта
"space-in-parens": ["error", "never"], // запрет отступов ( a,b)
"computed-property-spacing": ["error", "never"], // запрет лишних отступов в выражениях a[ i]
"array-bracket-spacing": ["error", "never"],
"no-multi-spaces": "error", // запрет лишних пробелов var a = 2
"no-sparse-arrays": "warn", // предупреждение при дырке в массиве
"no-mixed-spaces-and-tabs": "error", // нельзя миксовать табы и пробелы
"keyword-spacing": ["error", { "after": true }],
"comma-spacing": ["error", { "before": false, "after": true }], // отступ после запятой, а перед нельзя
"no-undef":"error",
"array-callback-return": "error" // коллбек методов массива типа arr.map arr.filter должны иметь return в коллбеке
},
"env": {
"browser": true,
"node": true
},
"globals": {
"Vue":true,
"Symbol":true,
"Promise":true,
},
"plugins": []
}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
logs/
.vscode/
package-lock.json
tests.js
config.test
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
ADAMANT Trading & Market making bot is a software that allows to run trades on crypto exchanges or make fake volume. Trading is a mode when bot run orders according to some strategy. It can be profitable or not.
In Market making mode, the bot places orders and execute them by himself, making a trade volume.
Trade bots work in ADAMANT Messenger chats directly.

Features:

* Managed with your commands using ADAMANT Messenger
* Easy to install and configure
* Free and open source
* Fill order books
* Market making
* Stores and displays statistics

Supported exchanges (more in progress):

* [IDCM](https://idcm.io/invitation/receive?code=LM5510&lang=en)

Available commands: ask a bot with `/help` command. Read more: [M]().

# Installation

## Requirements

* Ubuntu 16 / Ubuntu 18 (other OS had not been tested)
* NodeJS v 8+
* MongoDB ([installation instructions](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/))

## Setup

```
su - adamant
git clone https://github.com/Adamant-im/adamant-tradebot
cd ./adamant-tradebot
npm i
```

## Pre-launch tuning

```
nano config.json
```

Parameters:

* `exchange` <string> Exchange to work with. Available values see above. Case insensitive, obligatory.
* `pair` <string> Pair to with on the exchange. Obligatory.
* `apikey` <string> Exchange's account API key for connection. Obligatory.
* `apisecret` <string> Exchange's account API secret for connection. Obligatory.
* `apipassword` <string> Exchange's account trade password. If needed for exchange.
* `passPhrase` <string> The bot's secret phrase for accepting commands. Obligatory. Bot's ADM address will correspond this passPhrase.
* `admin_accounts` <string, array> ADAMANT accounts to accept commands from. Commands from other accounts will not be executed. At lease one account.
* `notify_non_admins` <boolean> Notify non-admins that they are not admins. If false, bot will be silent.
* `node_ADM` <string, array> List of nodes for API work, obligatorily
* `infoservice` <string, array> List of [ADAMANT InfoServices](https://github.com/Adamant-im/adamant-currencyinfo-services) for catching exchange rates, recommended
* `slack` <string> Token for Slack alerts for the bot’s administrator. No alerts if not set.
* `adamant_notify` <string> ADM address for the bot’s administrator. Recommended.
* `socket` <boolean> If to use WebSocket connection. Recommended for better user experience.
* `ws_type` <string> Choose socket connection, "ws" or "wss" depending on your server.
* `bot_name` <string> Bot's name for notifications.
* `welcome_string` <string> How to reply user in-chat, if unknown command received.

## Launching

You can start the Bot with the `node app` command, but it is recommended to use the process manager for this purpose.

```
pm2 start --name tradebot app.js
```

## Add Bot to cron

```
crontab -e
```

Add string:

```
@reboot cd /home/adamant/adamant-tradebot && pm2 start --name tradebot app.js
```

## Updating

```
su - adamant
cd ./adamant-tradebot
pm2 stop tradebot
mv config.json config_bup.json && git pull && mv config_bup.json config.json
npm i
pm2 start --name tradebot app.js
```
42 changes: 42 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const notify = require('./helpers/notify');
const db = require('./modules/DB');
const Store = require('./modules/Store');
const checker = require('./modules/checkerTransactions');
const doClearDB = process.argv.includes('clear_db');
const config = require('./modules/configReader');
const txParser = require('./modules/incomingTxsParser');
const log = require('./helpers/log');

// Socket connection
const api = require('./modules/api');
api.socket.initSocket({socket: config.socket, wsType: config.ws_type, onNewMessage: txParser, admAddress: Store.user.ADM.address});

setTimeout(init, 5000);

function init() {
require('./server');
try {
if (doClearDB) {
console.log('Clearing database..');
db.systemDb.db.drop();
db.incomingTxsDb.db.drop();
notify(`*${config.notifyName}: database cleared*. Manually stop the Bot now.`, 'info');
} else {

db.systemDb.findOne().then(system => {
if (system) {
Store.lastBlock = system.lastBlock;
} else { // if 1st start
Store.updateLastBlock();
}
checker();
require('./trade/mm_trader').run();
notify(`*${config.notifyName} started* for address _${Store.user.ADM.address}_ (ver. ${Store.version}).`, 'info');
});
}

} catch (e) {
notify(`${config.notifyName} is not started. Error: ${e}`, 'error');
process.exit(1);
}
}
75 changes: 75 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{

/** The bot's secret phrase for accepting commands.
Bot's ADM address will correspond this passPhrase.
**/
"passPhrase": "distance expect praise frequent..",

/** List of nodes to fetch transactions.
If one become unavailable, bot will choose live one.
**/

"node_ADM": [
"http://localhost:36666",
"https://endless.adamant.im",
"https://clown.adamant.im",
"https://bid.adamant.im",
"https://unusual.adamant.im",
"https://debate.adamant.im",
"http://185.231.245.26:36666",
"https://lake.adamant.im"
],

/** Socket connection is recommended for better user experience **/
"socket": true,

/** Choose socket connection, "ws" or "wss" depending on your server **/
"ws_type": "ws",

/** List of ADAMANT InfoServices for catching exchange rates **/
"infoservice": [
"https://info.adamant.im"
],

/** ADAMANT accounts to accept commands from. Commands from other accounts will not be executed. **/
"admin_accounts": [
"U123.."
],

/** Notify non-admins that they are not admins. If false, bot will be silent. **/
"notify_non_admins": true,

/** Exchange to work with. Available values: "idcm". Case insensitive. **/
"exchange": "IDCM",

/** Pair to trade **/
"pair": "ADM/BTC",

/** Exchange's account API key for connection **/
"apikey": "YOUR-KEY..",

/** Exchange's account API secret for connection **/
"apisecret": "YOUR-SECRET..",

/** Exchange's account trade password. If needed. **/
"apipassword": "YOUR-TRADE-PASS",

/** How to reply user in-chat, if first unknown command received. **/
"welcome_string": "Hi! 😊 I'm a trade and market making bot. ℹ️ Learn more about me on ADAMANT’s blog or type **/help** to see what I can.",

/** Bot's name for notifications **/
"bot_name": "Lovely Trade Bot",

/** ADAMANT address for notifications and monitoring (if needed, recommended) **/
"adamant_notify": "",

/** Slack key for notifications and monitoring (if needed) **/
"slack": "https://hooks.slack.com/services/...",

/** Port for getting debug info.
Do not set for live bots, use only for debugging.
Allows to get DBs records like http://ip:port/db?tb=incomingTxsDb
**/
"api": false

}
3 changes: 3 additions & 0 deletions helpers/const.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
SAT: 100000000
};
70 changes: 70 additions & 0 deletions helpers/dbModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
module.exports = (db) => {
return class {
constructor(data = {}, isSave) {
this.db = db;
Object.assign(this, data);
if (isSave){
this.save();
}
}
static get db() {
return db;
}
static find(a) { // return Array
return new Promise((resolve, reject) => {
this.db.find(a).toArray((err, data) => {
resolve(data.map(d=>new this(d)));
});
});
}
static aggregate(a) { // return Array
return new Promise((resolve, reject) => {
this.db.aggregate(a).toArray((err, data) => {
resolve(data.map(d=>new this(d)));
});
});
}
static findOne(a) {
return new Promise((resolve, reject) => {
db.findOne(a).then((doc, b) => {
if (!doc) {
resolve(doc);
} else {
resolve(new this(doc));
}
});
});
}
_data() {
const data = {};
for (let field in this){
if (!['db', '_id'].includes(field)){
data[field] = this[field];
}
}
return data;
}
async update(obj, isSave){
Object.assign(this, obj);
if (isSave){
await this.save();
}
}
save() {
return new Promise((resolve, reject) => {
if (!this._id) {
db.insertOne(this._data(), (err, res) => {
this._id = res.insertedId;
resolve(this._id);
});
} else {
db.updateOne({_id: this._id}, {
$set: this._data()
}, {upsert: true}).then(() => {
resolve(this._id);
});
}
});
}
};
};
Loading

0 comments on commit 6d54540

Please sign in to comment.