#install choco
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
#install NodeJS
choco install nodejs-lts
#install Git
choco install git
git clone https://github.com/donvadicastro/exchange-connector.git
cd exchange-connector
- install Docker Toolbox
- initialize
./scripts/raspberry-init.sh
- install Microsoft build tools
- run PowerShell console with admin rights
npm install --global --production windows-build-tools
npm config set msvs_version 2017 --global
npm install
npm install
- open "Docker terminal"
- run "
./scripts/run-kafks.sh
" script - do not close terminal
This project aims on creation of integration bridge to help execute financial operation with different clients based on action type involved.
Solution was developed using message-driven architecture, so all communications fulfilled through Kafka message bus.
This particular project was used to define and develop thin clients that will be responsible to process business events.
npm start
npm test
Worker is an nodeJS client that is connected to particular message queue and execute defined action based on defined instruction.
Initially contract of input message should be defined. All message contract are placed in "contracts/messages" folder and are represented as TypeScript interface.
Example:
export interface ICreateOrderMessage {
exchange: string;
symbol: string;
type: 'market' | 'limit';
side: 'buy' | 'sell';
amount: number;
price?: number;
params?: {};
}
All executors are stored in "process" folder and are represented as TypeScript class inherited from "ExchangeConnectorProcessBase" base class. Need to be implemented action that will be triggered on message.
To differentiate messages from different topics in single message handler - check kafkaMessage.topic
value.
Example:
import {ExchangeConnectorProcessBase} from "./base/processBase";
import {Message} from "kafka-node";
export class CreateOrder extends ExchangeConnectorProcessBase {
onMessage(message: ICreateOrderMessage, kafkaMessage: Message) {
const exchange = this.getExchange(message.exchange);
//handle invalid exchange properly
if(!exchange) {
return;
}
//check action is allowed on selected exchange
if(!exchange.has['createMarketOrder']) {
return this.kafkaClient.sendError(`"createMarketOrder" is not supported on "${message.exchange}"`);
}
console.log(`Order to be created on "${message.exchange}" with params: ${JSON.stringify(message)}`);
exchange.createOrder(message.symbol, message.type, message.side, message.amount, message.price, message.params)
.then((data: any) => this.send(data), (error: any) => this.sendError(error));
}
}
Once executor is created - it need to be registered in execution pipeline to be available to handle input messages. Registration should be added in "index.ts".
Example:
const client: KafkaClientExt = new KafkaClientExt();
//create executor instance, when
const createOrderProcess = new CreateOrder(client, ['topic-to-read-messages-from'], 'topic-to-generate-messages-to');
client.initialize().then(() => {
//start executor to handle events
createOrderProcess.run();
});
If actions are requires authentication - auth config for particular exchange need to be specified in "package.json" file in "ccxt -> exchange" section. Example:
"binance": {
"apiKey": "key",
"secret": "secret"
}
To check that worker is available and processed events correctly, test message can be triggered:
node tests/sendMessage.js <topicName> <message>
when:
- topicName - name of the topic data will be posted to
- message - string representation of message payload in JSON format.
Example:
"{\"exchange\": \"exmo\", \"symbol\": \"ZEC/USD\", \"type\": \"limit\", \"side\": \"buy\", \"amount\": 0.01, \"price\": 50}"