Merge pull request #39 from Superalgos/develop

May progress deployment
This commit is contained in:
benme authored and GitHub committed 2019-05-17 19:33:57 -03:00
commit 6c82b6322c
80 files changed
+434 -11678

No files matched your search

+23
View File
@@ -0,0 +1,23 @@
# Ignore files to be uploaded to the image
.env
.env.dev
.env.prod
.git
.gitignore
Dockerfile
Dockerfile.prod
README.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
/coverage
/.nyc_output
# VS Studio files
.vs/*
obj/*
bin/*
/.vscode
Project.njsproj
this.server.config.dev.json
+4
View File
@@ -0,0 +1,4 @@
NODE_ENV=production
PORT=4101
+9 -7
View File
@@ -2,14 +2,16 @@
.vs/*
obj/*
bin/*
/.vscode
node_modules/*
this.server.config.json
.env
dependency/
.env.dev
this.server.config.json
this.server.config.dev.json
\.nyc_output/
/node_modules
/dependency
coverage/*
\.vscode/
/.nyc_output
/coverage
debug.log
+10
View File
@@ -49,6 +49,16 @@ exports.newCopySimulator = function newCopySimulator(pStorage) {
parsedConfig.products[1].dataSets[1].filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day"
parsedConfig.products[1].dataSets[1].dataRange.filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily"
parsedConfig.products[2].storageAccount = pTeamCodeName
parsedConfig.products[2].dataSets[0].filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Market/@Period"
parsedConfig.products[2].dataSets[1].filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily/@Period/@Year/@Month/@Day"
parsedConfig.products[2].dataSets[1].dataRange.filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily"
parsedConfig.products[3].storageAccount = pTeamCodeName
parsedConfig.products[3].dataSets[0].filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Market/@Period"
parsedConfig.products[3].dataSets[1].filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily/@Period/@Year/@Month/@Day"
parsedConfig.products[3].dataSets[1].dataRange.filePath = pTeamCodeName + "/" + parsedConfig.codeName + ".1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily"
// Write the new files
let newSimulatorName = "simulator-" + pBotCodeName + "-Indicator-Bot"
let newSimulatorPath = "bots/" + newSimulatorName
+19
View File
@@ -0,0 +1,19 @@
FROM mhart/alpine-node:12
# Directory where the service will be installed
ARG API_DIR=/usr/src/saweb
# Prepare required directories
RUN mkdir -p ${API_DIR}
# Use app directory as current workdir
WORKDIR ${API_DIR}
# Copy package.json to workdir
COPY . ${API_DIR}/
# Install dependencies
RUN npm install --production
# Expose Port
EXPOSE $PORT
+21
View File
@@ -0,0 +1,21 @@
FROM mhart/alpine-node:8
ENV PORT=4101
RUN mkdir -p /var/www/app && \
mkdir -p /var/www/app/node_modules
# Use app directory as current workdir
WORKDIR /var/www/app
ENV PATH /var/www/app/node_modules/.bin:$PATH
# Copy package.json to workdir
COPY package.json /var/www/app/package.json
# Install dependencies
RUN npm install
# Copy application code
COPY . /var/www/app
# Expose Port
EXPOSE $PORT
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 64h-48V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H160V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V160h352v298c0 3.3-2.7 6-6 6z"/></svg>

After

Width:  |  Height:  |  Size: 349 B

+1 -2
View File
@@ -42,7 +42,6 @@
<Compile Include="Plotter.js" />
<Compile Include="PlotterPanel.js" />
<Compile Include="Server\BotsScripts.js" />
<Compile Include="Server\Exchange\ExchangeAPI.js" />
<Compile Include="Server\Exchange\exchangeUtils.js" />
<Compile Include="Server\Exchange\Wrappers\beautifier.js" />
<Compile Include="Server\Exchange\Wrappers\binance.js" />
@@ -129,4 +128,4 @@
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>
</Project>
+132 -125
View File
@@ -1,27 +1,24 @@
let dashboard;
let dashboard
function newAppLoader() {
function newAppLoader () {
const MODULE_NAME = 'App Loader'
const INFO_LOG = false
const ERROR_LOG = true
const INTENSIVE_LOG = false
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
const MODULE_NAME = "App Loader";
const INFO_LOG = false;
const ERROR_LOG = true;
const INTENSIVE_LOG = false;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
loadModules: loadModules
}
let thisObject = {
loadModules: loadModules
};
return thisObject
return thisObject;
function loadModules () {
try {
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> Entering function.') }
function loadModules() {
try {
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> Entering function."); }
let modulesArray = [
let modulesArray = [
/* CloudWebScripts */
@@ -29,127 +26,137 @@ function newAppLoader() {
/* PlotterPanels */
'Globals.js',
'Ecosystem.js',
'MQService',
"Globals.js",
"Ecosystem.js",
"MQService",
'TopSpace/CurrentEvent.js',
'TopSpace/EndUser.js',
'TopSpace/Login.js',
"TopSpace/CurrentEvent.js",
"TopSpace/EndUser.js",
"TopSpace/Login.js",
'StrategySpace/Workspace.js',
'StrategySpace/TradingSystem.js',
'StrategySpace/ConstGetStrategies.js',
'StrategySpace/ConstNewStrategy.js',
'StrategySpace/ConstUpdateStrategy.js',
'StrategySpace/ConstDeleteStrategy.js',
"Panels/TimeControlPanel.js",
"Panels/ProductsPanel.js",
"Panels/PanelTabButton.js",
'Utilities/RoundedCornersBackground.js',
"Spaces/BottomSpace.js",
"Spaces/TopSpace.js",
"Spaces/PanelsSpace.js",
"Spaces/ChartSpace.js",
"Spaces/FloatingSpace.js",
'Panels/TimeControlPanel.js',
'Panels/ProductsPanel.js',
'Panels/PanelTabButton.js',
'Panels/ProductCard.js',
"Files/SingleFile.js",
"Files/FileCloud.js",
"Files/MarketFiles.js",
"Files/DailyFiles.js",
"Files/FileCursor.js",
"Files/FileSequence.js",
"Files/FileStorage.js",
'ControlsToolBox/SidePanel.js',
'ControlsToolBox/SidePanelTab.js',
"FloatingSpace/NoteSets.js",
"FloatingSpace/Note.js",
"FloatingSpace/ProfileBalls.js",
"FloatingSpace/ProfileBall.js",
"FloatingSpace/FloatingObject.js",
"FloatingSpace/FloatingLayer.js",
'Spaces/CockpitSpace.js',
'Spaces/TopSpace.js',
'Spaces/PanelsSpace.js',
'Spaces/ChartSpace.js',
'Spaces/FloatingSpace.js',
'Spaces/StrategySpace.js',
"Exchange/ExchangeAPI.js",
'Files/SingleFile.js',
'Files/FileCloud.js',
'Files/MarketFiles.js',
'Files/DailyFiles.js',
'Files/FileCursor.js',
'Files/FileSequence.js',
'Files/FileStorage.js',
"Scales/RateScale.js",
"Scales/TimeScale.js",
"Scales/TimePeriodScale.js",
'FloatingSpace/NoteSets.js',
'FloatingSpace/Note.js',
'FloatingSpace/ProfileBalls.js',
'FloatingSpace/ProfileBall.js',
'FloatingSpace/FloatingObject.js',
'FloatingSpace/FloatingLayer.js',
'FloatingSpace/StrategyPartConstructor.js',
'FloatingSpace/StrategyPart.js',
'FloatingSpace/StrategyPartTitle.js',
'FloatingSpace/CircularMenu.js',
'FloatingSpace/CircularMenuItem.js',
'FloatingSpace/CodeEditor.js',
"Plotter.js",
"PlotterPanel.js",
'Scales/RateScale.js',
'Scales/TimeScale.js',
'Scales/TimePeriodScale.js',
'Scales/Commons.js',
"PlottersManager.js",
"ProductStorage.js",
"CompetitionStorage.js",
"ProductCard.js",
'ChartsSpace/ChartUtilities.js',
'ChartsSpace/PlottersManager.js',
'ChartsSpace/TimelineChart.js',
'ChartsSpace/TimeMachine.js',
'ChartsSpace/ViewPort.js',
'ChartsSpace/TimeLineCoordinateSystem.js',
"SplashScreen.js",
"Canvas.js",
"EventHandler.js",
"Frame.js",
'CockpitSpace/AssetBalances.js',
'CockpitSpace/Speedometer.js',
'CockpitSpace/RestartSimulation.js',
'CockpitSpace/GraphQLRestartSimulation.js',
"ViewPort.js",
"TimeMachine.js",
"Candle.js",
"VolumeBar.js",
"ChartUtilities.js",
"TimelineChart.js",
"Animation.js",
'Plotter.js',
'PlotterPanel.js',
"Container.js",
"Displace.js",
'ProductStorage.js',
'CompetitionStorage.js',
"Azure/azure-storage.blob.js",
"TimeLineCoordinateSystem.js",
"Utilities.js",
"Dashboard.js"
];
'SplashScreen.js',
'Canvas.js',
'EventHandler.js',
'Frame.js',
let downloadedCounter = 0;
let versionParam = window.canvasApp.version;
if (versionParam === undefined) { versionParam = ''; }
else {
versionParam = '?' + versionParam;
'Animation.js',
'Container.js',
'Displace.js',
'Azure/azure-storage.blob.js',
'Utilities.js',
'Dashboard.js'
]
let downloadedCounter = 0
let versionParam = window.canvasApp.version
if (versionParam === undefined) { versionParam = '' } else {
versionParam = '?' + versionParam
}
for (let i = 0; i < modulesArray.length; i++) {
let path = window.canvasApp.urlPrefix + modulesArray[i] + versionParam
REQUIREJS([path], onRequired)
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> Module Requested.') }
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> path = ' + path) }
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> total requested = ' + (i + 1)) }
function onRequired (pModule) {
try {
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> Entering function.') }
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> Module Downloaded.') }
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> path = ' + path) }
downloadedCounter++
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> downloadedCounter = ' + downloadedCounter) }
if (downloadedCounter === modulesArray.length) {
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> Starting Advanced Algos Platform.') }
dashboard = newDashboard()
dashboard.start()
}
for (let i = 0; i < modulesArray.length; i++) {
let path = window.canvasApp.urlPrefix + modulesArray[i] + versionParam;
REQUIREJS([path], onRequired);
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> Module Requested."); }
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> path = " + path); }
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> total requested = " + (i + 1)); }
function onRequired(pModule) {
try {
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> onRequired -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> onRequired -> Module Downloaded."); }
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> onRequired -> path = " + path); }
downloadedCounter++;
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> onRequired -> downloadedCounter = " + downloadedCounter); }
if (downloadedCounter === modulesArray.length) {
if (INFO_LOG === true) { logger.write("[INFO] loadModules -> onRequired -> Starting Advanced Algos Platform."); }
dashboard = newDashboard();
dashboard.start();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] loadModules -> onRequired -> err = " + err); }
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] loadModules -> err = " + err); }
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] loadModules -> onRequired -> err = ' + err) }
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] loadModules -> err = ' + err) }
}
}
}
}
+31
View File
@@ -45,6 +45,35 @@ function loadAdvancedAlgosPlatform() {
/* The first thing to do here is to add the canvas where all the action is going to happen. */
let textArea = document.createElement('textarea');
textArea.id = "textArea";
textArea.spellcheck = false;
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + 'Saira' + ';' +
'font-size: 12px;' +
'background-color: rgb(255, 255, 255);' +
'color:rgb(255, 255, 255);' +
'width: ' + 800 + 'px;' +
'height: ' + 600 + 'px'
let textAreaDiv = document.getElementById('textAreaDiv');
textAreaDiv.appendChild(textArea);
textAreaDiv.style = 'position:fixed; top:' + -1500 + 'px; left:' + 500 + 'px; z-index:10; '
let input = document.createElement('input');
input.id = "input";
input.spellcheck = false;
input.style = "border: none; outline: none; box-shadow: none; overflow:hidden; width: 0px; height: 0px;";
let inputDiv = document.getElementById('inputDiv');
inputDiv.appendChild(input);
let canvas = document.createElement('canvas');
canvas.id = "canvas";
@@ -64,6 +93,8 @@ function loadAdvancedAlgosPlatform() {
browserCanvas.style.top = window.canvasApp.topMargin + 'px';
loadDebugModule();
function loadDebugModule() {
-310
View File
@@ -1,310 +0,0 @@
exports.newExchangeAPI = function newExchangeAPI(logger, authToken) {
/*
This module allows trading bots to connect to the exchange and do trading operations on it. So far it can only work with Poloniex.
*/
const _ = require('lodash')
const isValidOrder = require('./exchangeUtils').isValidOrder
const axios = require('axios')
let MODULE_NAME = "Exchange API";
let thisObject = {
initialize: initialize,
getTicker: getTicker,
getOpenPositions: getOpenPositions,
getExecutedTrades: getExecutedTrades,
putPosition: putPosition,
movePosition: movePosition,
getPublicTradeHistory: getPublicTradeHistory,
getExchangeProperties: getExchangeProperties,
getMaxDecimalPositions: getMaxDecimalPositions
};
let apiClient;
return thisObject;
async function initialize(callBackFunction) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
let botExchange = 'Poloniex';
let exchange = botExchange.toLowerCase() + 'Client.js';
let api = require('./wrappers/' + exchange);
let accessToken
let keyId
let cloneId
if (global.CURRENT_EXECUTION_AT === "Cloud") {
keyId = process.env.KEY_ID
cloneId = process.env.CLONE_ID
let auth = require('../utils/auth')
let authTokenCloud = await auth.authenticate()
accessToken = 'Bearer ' + authTokenCloud
} else if (global.CURRENT_EXECUTION_AT === "Browser") {
accessToken = 'Bearer ' + authToken
}
let keyVaultAPI = createKeyVaultAPIClient(accessToken, keyId, cloneId)
apiClient = api.newAPIClient(keyVaultAPI, logger);
callBackFunction(global.DEFAULT_OK_RESPONSE);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function createKeyVaultAPIClient(accessToken, keyId, cloneId) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); }
const keyVaultAPI = {}
keyVaultAPI.signTransaction = function (transaction, next) {
axios({
url: global.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
mutation keyVault_SignTransaction($transaction: String!, $keyId: String, $cloneId: String){
keyVault_SignTransaction(transaction: $transaction, keyId: $keyId, cloneId: $cloneId){
key,
signature,
date
}
}
`,
variables: {
transaction: transaction,
keyId: keyId,
cloneId: cloneId
}
},
headers: {
authorization: accessToken
}
}).then(res => {
if (res.errors) {
next(undefined, 'Error from graphql: ' + res.errors);
} else {
let signature = {
Key: res.data.data.keyVault_SignTransaction.key,
Sign: res.data.data.keyVault_SignTransaction.signature
}
next(signature)
}
}).catch(error => {
next(undefined, 'Error signing the message on the key vault: ' + error.message);
});
}
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Returning graphql client."); }
return keyVaultAPI;
}
/*
* Position Object = {
* id, String
* type, String
* rate, Number
* amountA, Number
* amountB, Number
* fee, Number
* datetime Date
* };
*/
function truncDecimals(pFloatValue) {
let decimals = getMaxDecimalPositions();
return parseFloat(parseFloat(pFloatValue).toFixed(decimals));
}
/*
* Return number of decimals for the current market
*/
function getMaxDecimalPositions() {
return getMarketConfig().maxDecimals;
}
/*
* Return number of decimals for the current market
*/
function getMarketConfig() {
return _.find(getExchangeProperties().markets, (p) => {
return _.first(p.pair) === global.MARKET.assetA.toUpperCase() &&
_.last(p.pair) === global.MARKET.assetB.toUpperCase();
});
}
/*
* Return number of decimals for the current market
*/
function getExchangeProperties() {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExchangeProperties -> Entering function."); }
return apiClient.getExchangeProperties();
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] getExchangeProperties -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Returns the price for a given pair of assets.
* The object returned is an array of trades:
* ticker = {
* bid, Number
* ask, Number
* last Number
* };
*/
function getTicker(pMarket, callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTicker -> Entering function."); }
apiClient.getTicker(pMarket, callBack);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] getTicker -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Returns the open positions ath the exchange for a given market and user account.
* The object returned is an array of positions
*
*/
function getOpenPositions(pMarket, callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> pMarket = " + JSON.stringify(pMarket)); }
apiClient.getOpenPositions(pMarket, callBack);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] getOpenPositions -> Error = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Returns the trades for a given order number.
* The object returned is an array of positions
*/
function getExecutedTrades(pPositionId, callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> pPositionId = " + pPositionId); }
apiClient.getExecutedTrades(pPositionId, callBack);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] getExecutedTrades -> Error = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Creates a new buy or sell order.
* The orderNumber is returned. String
*/
function putPosition(pMarket, pType, pRate, pAmountA, pAmountB, callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pMarket = " + JSON.stringify(pMarket)); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + truncDecimals(pRate)); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + truncDecimals(pAmountA)); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + truncDecimals(pAmountB)); }
let check = isValidOrder({
market: getMarketConfig(),
api: apiClient,
amount: truncDecimals(pAmountB),
price: truncDecimals(pRate)
});
if (check.valid) {
if (pType === "buy") {
apiClient.buy(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack);
return;
}
if (pType === "sell") {
apiClient.sell(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack);
return;
}
logger.write(MODULE_NAME, "[ERROR] putPosition -> pType must be either 'buy' or 'sell'.");
callBack(global.DEFAULT_FAIL_RESPONSE);
} else {
logger.write(MODULE_NAME, "[ERROR] putPosition -> The order is invalid: " + check.reason);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] putPosition -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Move an existing position to the new rate.
* The new orderNumber is returned.
*/
function movePosition(pPosition, pNewRate, pNewAmountB, callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pPosition = " + JSON.stringify(pPosition)); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pNewRate = " + truncDecimals(pNewRate)); }
apiClient.movePosition(pPosition, truncDecimals(pNewRate), truncDecimals(pNewAmountB), callBack);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] movePosition -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId.
* It's possible that the exchange doesn't support this method.
* The object returned is an array of trades:
* trade = {
* tradeID, String
* globalTradeID, String
* type, String
* rate, Number
* amountA, Number
* amountB, Number
* date Date
* };
*/
function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTradeHistory -> Entering function."); }
apiClient.getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] getTradeHistory -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
};
-183
View File
@@ -1,183 +0,0 @@
const _ = require('underscore');
class Beautifier {
constructor() {
this._beautifications = {
aggTrades: {
a: 'aggTradeId',
p: 'price',
q: 'quantity',
f: 'firstTradeId',
l: 'lastTradeId',
T: 'timestamp',
m: 'maker',
M: 'bestPriceMatch'
},
klines: {
0: 'openTime',
1: 'open',
2: 'high',
3: 'low',
4: 'close',
5: 'volume',
6: 'closeTime',
7: 'quoteAssetVolume',
8: 'trades',
9: 'takerBaseAssetVolume',
10: 'takerQuoteAssetVolume',
11: 'ignored'
},
bids: [
{
0: 'price',
1: 'quantity',
2: 'ignored'
}
],
asks: [
{
0: 'price',
1: 'quantity',
2: 'ignored'
}
],
depthUpdateEvent: {
e: 'eventType',
E: 'eventTime',
s: 'symbol',
u: 'updateId',
b: 'bidDepthDelta',
a: 'askDepthDelta'
},
bidDepthDelta: [
{
0: 'price',
1: 'quantity',
2: 'ignored'
}
],
askDepthDelta: [
{
0: 'price',
1: 'quantity',
2: 'ignored'
}
],
klineEvent: {
e: 'eventType',
E: 'eventTime',
s: 'symbol',
k: 'kline'
},
kline: {
t: 'startTime',
T: 'endTime',
s: 'symbol',
i: 'interval',
f: 'firstTradeId',
L: 'lastTradeId',
o: 'open',
c: 'close',
h: 'high',
l: 'low',
v: 'volume',
n: 'trades',
x: 'final',
q: 'quoteVolume',
V: 'volumeActive',
Q: 'quoteVolumeActive',
B: 'ignored'
},
aggTradeEvent: {
e: 'eventType',
E: 'eventTime',
s: 'symbol',
a: 'tradeId',
p: 'price',
q: 'quantity',
f: 'firstTradeId',
l: 'lastTradeId',
T: 'time',
m: 'maker',
M: 'ignored'
},
outboundAccountInfoEvent: {
e: 'eventType',
E: 'eventTime',
m: 'makerCommission',
t: 'takerCommission',
b: 'buyerCommission',
s: 'sellerCommission',
T: 'canTrade',
W: 'canWithdraw',
D: 'canDeposit',
B: 'balances'
},
balances: [
{
a: 'asset',
f: 'availableBalance',
l: 'onOrderBalance'
}
],
executionReportEvent: {
e: 'eventType',
E: 'eventTime',
s: 'symbol',
c: 'newClientOrderId',
S: 'side',
o: 'orderType',
f: 'cancelType', // GTC 'Good till Cancel', IOC: 'Immediate or Cancel'
q: 'quantity',
p: 'price',
x: 'executionType',
X: 'orderStatus',
r: 'rejectReason',
i: 'orderId',
l: 'lastTradeQuantity',
z: 'accumulatedQuantity',
L: 'lastTradePrice',
n: 'commission',
N: 'commissionAsset',
m: 'maker',
T: 'tradeTime',
t: 'tradeId'
}
}
}
beautify(object, type) {
const beautifications = _.isObject(type) ? type : this._beautifications[type];
if (!beautifications) {
return object;
}
let newItem = {};
_.each(object, (value, key) => {
if (_.isArray(value)) {
const newArray = [];
if (_.isArray(this._beautifications[beautifications[key]])) {
_.each(value, arrayValue => {
newArray.push(this.beautify(arrayValue, this._beautifications[beautifications[key]][0]));
});
} else {
_.each(value, (value, key) => {
newItem.push(this.beautify(value, beautifications[key]))
});
}
const newKey = beautifications[key] || key;
newItem[newKey] = newArray;
} else if (_.isObject(value)) {
const newKey = beautifications[key] || key;
newItem[newKey] = this.beautify(value, beautifications[key]);
} else {
const newKey = beautifications[key] || key;
newItem[newKey] = value;
}
});
return newItem;
}
}
module.exports = Beautifier;
-368
View File
@@ -1,368 +0,0 @@
// Source: https://github.com/zoeyg/binance/blob/master/lib/rest.js
const request = require('request');
const qs = require('querystring');
const _ = require('underscore');
const crypto = require('crypto');
const Beautifier = require('./beautifier.js');
const assert = require('assert');
class BinanceRest {
constructor({
key,
secret,
recvWindow = false,
timeout = 15000,
disableBeautification = false,
handleDrift = false
}) {
this.key = key;
this.secret = secret;
this.recvWindow = recvWindow;
this.timeout = timeout;
this.disableBeautification = disableBeautification;
this.handleDrift = handleDrift;
this._beautifier = new Beautifier();
this._baseUrl = 'https://api.binance.com/';
this._drift = 0;
this._syncInterval = 0;
}
_makeRequest(query, callback, route, security, method, attempt = 0) {
assert(_.isUndefined(callback) || _.isFunction(callback), 'callback must be a function or undefined');
assert(_.isObject(query), 'query must be an object');
let queryString;
const type = _.last(route.split('/')),
options = {
url: `${this._baseUrl}${route}`,
timeout: this.timeout
};
if (security === 'SIGNED') {
if (this.recvWindow) {
query.recvWindow = this.recvWindow;
}
queryString = qs.stringify(query);
options.url += '?' + queryString;
if (options.url.substr(options.url.length - 1) !== '?') {
options.url += '&';
}
options.url += `signature=${this._sign(queryString)}`;
} else {
queryString = qs.stringify(query);
if (queryString) {
options.url += '?' + queryString;
}
}
if (security === 'API-KEY' || security === 'SIGNED') {
options.headers = { 'X-MBX-APIKEY': this.key };
}
if (method) {
options.method = method;
}
const action = cb => {
request(options, (err, response, body) => {
let payload;
try {
payload = JSON.parse(body);
} catch (e) {
payload = body;
}
if (err) {
cb(err, payload);
} else if (response.statusCode < 200 || response.statusCode > 299) {
/*
* If we get a response that the timestamp is ahead of the server,
* calculate the drift and then attempt the request again
*/
if (response.statusCode === 400 && payload.code === -1021 &&
this.handleDrift && attempt === 0) {
this.calculateDrift()
.then(() => {
query.timestamp = this._getTime() + this._drift;
return this._makeRequest(query, cb, route, security, method,
++attempt);
});
} else {
cb(new Error(`Response code ${response.statusCode}`), payload);
}
} else {
if (_.isArray(payload)) {
payload = _.map(payload, (item) => {
return this._doBeautifications(item, type);
});
} else {
payload = this._doBeautifications(payload);
}
cb(err, payload);
}
});
};
if (callback) {
action(callback);
} else {
return new Promise((resolve, reject) => action((err, payload) => {
if (err) {
if (payload === undefined) {
reject(err);
} else {
reject(payload);
}
} else {
resolve(payload);
}
}));
}
}
_doBeautifications(response, route) {
if (this.disableBeautification) {
return response;
}
return this._beautifier.beautify(response, route);
}
_sign(queryString) {
return crypto.createHmac('sha256', this.secret)
.update(queryString)
.digest('hex');
}
_setTimestamp(query) {
if (!query.timestamp) {
query.timestamp = this._getTime() + this._drift;
}
}
_getTime() {
return new Date().getTime();
}
calculateDrift() {
const systemTime = this._getTime();
return this.time()
.then((response) => {
// Calculate the approximate trip time from here to binance
const transitTime = parseInt((this._getTime() - systemTime) / 2);
this._drift = response.serverTime - (systemTime + transitTime);
});
}
startTimeSync(interval = 300000, onRecalculateDriftCb) {
return new Promise((resolve, reject) => {
// If there's already an interval running, clear it and reset values
if (this._syncInterval !== 0) {
this.endTimeSync();
return resolve();
}
// Calculate initial drift value and setup interval to periodically update it
this.calculateDrift()
.then(resolve)
.catch(reject);
this._syncInterval = setInterval(() => {
const promise = this.calculateDrift();
if (_.isFunction(onRecalculateDriftCb)) {
onRecalculateDriftCb(promise);
}
}, interval);
});
}
endTimeSync() {
clearInterval(this._syncInterval);
this._drift = 0;
this._syncInterval = 0;
}
// Public APIs
ping(callback) {
return this._makeRequest({}, callback, 'api/v1/ping');
}
time(callback) {
return this._makeRequest({}, callback, 'api/v1/time');
}
depth(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v1/depth');
}
trades(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v1/trades');
}
historicalTrades(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v1/historicalTrades', 'API-KEY');
}
aggTrades(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v1/aggTrades');
}
exchangeInfo(callback) {
return this._makeRequest({}, callback, 'api/v1/exchangeInfo');
}
klines(query = {}, callback) {
return this._makeRequest(query, callback, 'api/v1/klines');
}
ticker24hr(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v1/ticker/24hr');
}
tickerPrice(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v3/ticker/price');
}
bookTicker(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
return this._makeRequest(query, callback, 'api/v3/ticker/bookTicker');
}
allBookTickers(callback) {
return this._makeRequest({}, callback, 'api/v1/ticker/allBookTickers');
}
allPrices(callback) {
return this._makeRequest({}, callback, 'api/v1/ticker/allPrices');
}
// Private APIs
newOrder(query = {}, callback) {
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'POST');
}
testOrder(query = {}, callback) {
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/order/test', 'SIGNED', 'POST');
}
queryOrder(query = {}, callback) {
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED');
}
cancelOrder(query = {}, callback) {
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'DELETE');
}
openOrders(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/openOrders', 'SIGNED');
}
allOrders(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/allOrders', 'SIGNED');
}
account(query = {}, callback) {
if (_.isFunction(query)) {
callback = query;
query = {};
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/account', 'SIGNED');
}
myTrades(query = {}, callback) {
if (_.isString(query)) {
query = { symbol: query };
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'api/v3/myTrades', 'SIGNED');
}
withdraw(query = {}, callback) {
this._setTimestamp(query);
return this._makeRequest(query, callback, 'wapi/v3/withdraw.html', 'SIGNED', 'POST');
}
depositHistory(query = {}, callback) {
if (_.isString(query)) {
query = { asset: query };
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'wapi/v3/depositHistory.html', 'SIGNED');
}
withdrawHistory(query = {}, callback) {
if (_.isString(query)) {
query = { asset: query };
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'wapi/v3/withdrawHistory.html', 'SIGNED');
}
depositAddress(query = {}, callback) {
if (_.isString(query)) {
query = { asset: query };
}
this._setTimestamp(query);
return this._makeRequest(query, callback, 'wapi/v3/depositAddress.html', 'SIGNED');
}
accountStatus(callback) {
const query = {};
this._setTimestamp(query);
return this._makeRequest(query, callback, 'wapi/v3/accountStatus.html', 'SIGNED');
}
startUserDataStream(callback) {
return this._makeRequest({}, callback, 'api/v1/userDataStream', 'API-KEY', 'POST');
}
keepAliveUserDataStream(query = {}, callback) {
return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'PUT');
}
closeUserDataStream(query = {}, callback) {
return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'DELETE');
}
}
module.exports = BinanceRest;
-360
View File
@@ -1,360 +0,0 @@
exports.newAPIClient = function newAPIClient(pKey, pSecret) {
/*
/* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications.
/* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one.
*/
const FULL_LOG = true;
const LOG_FILE_CONTENT = true;
const MODULE_NAME = "binanceClient";
const retry = require('../exchangeUtils').retry;
const includes = require('../exchangeUtils').includes;
const _ = require('lodash');
const Binance = require("./binance");
const exchangeProperties = require('./poloniexProperties.json');
const recoverableErrors = [
'SOCKETTIMEDOUT',
'TIMEDOUT',
'CONNRESET',
'CONNREFUSED',
'NOTFOUND',
'Error -1021',
'Response code 429',
'Response code 5',
'ETIMEDOUT'
];
let API = new Binance({
key: pKey,
secret: pSecret,
timeout: 15000,
recvWindow: 60000,
disableBeautification: false,
handleDrift: true,
});
let thisObject = {
getTicker: getTicker,
getOpenPositions: getOpenPositions,
getExecutedTrades: getExecutedTrades,
buy: buy,
sell: sell,
movePosition: movePosition,
getPublicTradeHistory: getPublicTradeHistory,
getExchangeProperties: getExchangeProperties,
isValidPrice: isValidPrice,
isValidLot: isValidLot
};
return thisObject;
function joinCurrencies(currencyA, currencyB) {
// If only one arg, then return the first
if (typeof currencyB !== 'string') {
return currencyA;
}
return currencyB + '' + currencyA;
}
/*
* Returns the properties for this exchange
*/
function getExchangeProperties() {
return exchangeProperties;
}
function truncDecimals(pFloatValue) {
let decimals = 6;
return parseFloat(parseFloat(pFloatValue).toFixed(decimals));
}
/*
* Returns the price for a given pair of assets.
* The object returned is an array of trades:
* ticker = {
* bid, Number
* ask, Number
* last Number
* };
*/
function getTicker(pMarket, callBack) {
let market = joinCurrencies(pMarket.assetA, pMarket.assetB);
const handle = (err, response) => {
let ticker;
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
ticker = {
bid: Number(response.bidPrice),
ask: Number(response.askPrice),
last: Number(response.lastPrice)
};
}
callBack(err, ticker);
};
const fetch = next => API.ticker24hr(market, analizeResponse(next));
retry(null, fetch, handle);
}
/*
* Returns the open positions ath the exchange for a given market and user account.
* The object returned is an array of positions:
* position = {
* id,
* type,
* rate, Number
* amountA, Number
* amountB, Number
* fee, (not required) Number
* datetime
* };
*/
function getOpenPositions(pMarket, callBack) {
let market = joinCurrencies(pMarket.assetA, pMarket.assetB);
const handle = (err, response) => {
let exchangePositions = [];
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
for (let i = 0; i < response.length; i++) {
let openPosition = {
id: response[i].orderId,
type: response[i].side.toLowerCase(),
rate: Number(response[i].price),
amountA: truncDecimals(response[i].origQty * response[i].price),
amountB: Number(response[i].origQty),
date: (new Date(response[i].time)).valueOf()
};
exchangePositions.push(openPosition);
}
}
callBack(err, exchangePositions);
};
const fetch = next => API.openOrders(market, analizeResponse(next));
retry(null, fetch, handle);
}
/*
* Returns the trades for a given order number.
* The object returned is an array of positions:
* position = {
* id,
* type,
* rate, Number
* amountA, Number
* amountB, Number
* fee, Number
* datetime
* };
*/
function getExecutedTrades(pPositionId, callBack) {
let market = joinCurrencies(global.MARKET.assetA, global.MARKET.assetB);
const handle = (err, response) => {
let exchangeTrades = [];
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
for (let i = 0; i < response.length; i++) {
if (response[i].orderId === pPositionId) {
let type = "sell"
if (response[i].isBuyer === true) {
type = "buy";
}
let trade = {
id: response[i].orderId,
type: type,
rate: Number(response[i].price),
amountA: truncDecimals(response[i].qty * response[i].price),
amountB: Number(response[i].qty),
fee: Number(response[i].commission),
date: (new Date(response[i].time)).valueOf()
};
exchangeTrades.push(trade);
break;
}
}
}
callBack(err, exchangeTrades);
};
const fetch = next => API.myTrades(market, analizeResponse(next));
retry(null, fetch, handle);
}
/*
* Creates a new buy order.
* The orderNumber is returned.
*/
function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) {
var parameters = {
symbol: joinCurrencies(pCurrencyA, pCurrencyB),
side: 'BUY',
type: 'LIMIT',
quantity: pAmount,
price: pRate,
timeInForce: 'GTC'
};
const handle = (err, response) => {
let orderNumber;
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
orderNumber = response.orderId;
}
callBack(err, orderNumber);
};
const fetch = next => API.newOrder(parameters, analizeResponse(next));
retry(null, fetch, handle);
}
/*
* Creates a new sell order.
* The orderNumber is returned. String
*/
function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) {
var parameters = {
symbol: joinCurrencies(pCurrencyA, pCurrencyB),
side: 'SELL',
type: 'LIMIT',
quantity: pAmount,
price: pRate,
timeInForce: 'GTC'
};
const handle = (err, response) => {
let orderNumber;
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
orderNumber = response.orderId;
}
callBack(err, orderNumber);
};
const fetch = next => API.newOrder(parameters, analizeResponse(next));
retry(null, fetch, handle);
}
/* //TODO Complete partial orders
* Move an existing position to the new rate.
* The new orderNumber is returned. String
*/
function movePosition(pPosition, pNewRate, pNewAmountB, callBack) {
var parameters = {
symbol: joinCurrencies(global.MARKET.assetA, global.MARKET.assetB),
orderId: pPosition.id
};
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { console.log("[INFO] moveOrder -> Step1 - Cancelling Position: " + JSON.stringify(pPosition)); }
const handle = (err, response) => {
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { console.log("[INFO] moveOrder -> Step1 Complete - Position Cancelled. Proceeding to put the new position."); }
if (position.type === "buy")
thisObject.buy(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack);
else
thisObject.sell(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack);
} else {
callBack(err);
}
};
const fetch = next => API.cancelOrder(parameters, analizeResponse(next));
retry(null, fetch, handle);
}
/* //TODO Pending Review
* Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId.
* It's possible that the exchange doesn't support this method.
* The object returned is an array of trades:
* trade = {
* tradeIdAtExchange,
* marketIdAtExchange,
* type,
* rate, Number
* amountA, Number
* amountB, Number
* datetime
* };
*/
function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) {
if (CONSOLE_LOG === true) { console.log("[INFO] getPublicTradeHistory -> Not implemented yet."); }
callBack(global.DEFAULT_FAIL_RESPONSE);
}
function isValidPrice(price) {
return price >= market.minimalOrder.price;
}
function isValidLot(price, amount) {
return amount * price >= market.minimalOrder.order;
}
function analizeResponse(callBack) {
return (exchangeErr, exchangeResponse) => {
let error;
/* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */
let stringExchangeErr = JSON.stringify(exchangeErr);
let stringExchangeResponse = JSON.stringify(exchangeResponse);
try {
if (CONSOLE_LOG === true) { console.log("[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); }
if (CONSOLE_LOG === true) { console.log("[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); }
if (exchangeErr) {
error = global.DEFAULT_FAIL_RESPONSE;
} else if (!exchangeResponse) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: 'Empty response'
};
} else if (includes(exchangeResponse.error, ['<!DOCTYPE html>'])) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: exchangeResponse
};
} else if (includes(exchangeResponse.error, ['Order does not exist.'])) {
error = {
result: global.CUSTOM_OK_RESPONSE.result,
message: exchangeResponse.error
};
} else if (exchangeResponse.error) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: exchangeResponse.error
};
}
if (error) {
if (includes(error.message, recoverableErrors)) {
error.notFatal = true;
}
}
return callBack(error, exchangeResponse);
} catch (err) {
console.log("[ERROR] analizeResponse -> err.message = " + err.message);
return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse);
}
}
}
}
File diff suppressed because it is too large. Load diff
-440
View File
@@ -1,440 +0,0 @@
// Source: https://github.com/premasagar/poloniex.js
// Documentation: https://poloniex.com/support/api/
module.exports = (function () {
'use strict';
// Module dependencies
var request = require('request'),
nonce = require('nonce')();
// Constants
var version = '0.0.9',
PUBLIC_API_URL = 'https://poloniex.com/public',
PRIVATE_API_URL = 'https://poloniex.com/tradingApi',
USER_AGENT = 'poloniex.js ' + version;
//USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0'
// Helper methods
function joinCurrencies(currencyA, currencyB) {
// If only one arg, then return the first
if (typeof currencyB !== 'string') {
return currencyA;
}
return currencyA + '_' + currencyB;
}
// Constructor
function Poloniex(keyVaultAPI) {
// Generate headers signed by this user's key and secret.
// The secret is encapsulated and never exposed
this._getPrivateHeaders = function (parameters, next) {
var paramString, signature;
// Convert to `arg1=foo&arg2=bar`
paramString = Object.keys(parameters).map(function (param) {
return encodeURIComponent(param) + '=' + encodeURIComponent(parameters[param]);
}).join('&');
keyVaultAPI.signTransaction(paramString, next);
};
}
// Currently, this fails with `Error: CERT_UNTRUSTED`
// Poloniex.STRICT_SSL can be set to `false` to avoid this. Use with caution.
// Will be removed in future, once this is resolved.
Poloniex.STRICT_SSL = true;
// Customisable user agent string
Poloniex.USER_AGENT = USER_AGENT;
// Prototype
Poloniex.prototype = {
constructor: Poloniex,
// Make an API request
_request: function (options, callback) {
if (!('headers' in options)) {
options.headers = {};
}
options.json = true;
options.headers['User-Agent'] = Poloniex.USER_AGENT;
options.strictSSL = Poloniex.STRICT_SSL;
options.timeout = 60 * 1000;
request(options, function (err, response, body) {
// Empty response
if (!err && (typeof body === 'undefined' || body === null)) {
err = 'Empty response';
}
callback(err, body);
});
return this;
},
// Make a public API request
_public: function (command, parameters, callback) {
var options;
if (typeof parameters === 'function') {
callback = parameters;
parameters = {};
}
parameters || (parameters = {});
parameters.command = command;
options = {
method: 'GET',
url: PUBLIC_API_URL,
qs: parameters
};
options.qs.command = command;
return this._request(options, callback);
},
// Make a private API request
_private: function (command, parameters, callback) {
var options;
if (typeof parameters === 'function') {
callback = parameters;
parameters = {};
}
parameters || (parameters = {});
parameters.command = command;
parameters.nonce = nonce();
options = {
method: 'POST',
url: PRIVATE_API_URL,
form: parameters
};
let headers = this._getPrivateHeaders(parameters, next)
let thisObject = this
function next(pHeaders, error) {
if (!error) {
options.headers = pHeaders;
return thisObject._request(options, callback);
} else {
callback(error);
}
}
},
/////
// PUBLIC METHODS
returnTicker: function (callback) {
return this._public('returnTicker', callback);
},
return24hVolume: function (callback) {
return this._public('return24hVolume', callback);
},
returnOrderBook: function (currencyA, currencyB, callback) {
var currencyPair;
if (typeof currencyB === 'function') {
currencyPair = currencyA;
callback = currencyB;
currencyB = null;
}
else {
currencyPair = joinCurrencies(currencyA, currencyB);
}
var parameters = {
currencyPair: currencyPair
};
return this._public('returnOrderBook', parameters, callback);
},
returnChartData: function (currencyA, currencyB, period, start, end, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
period: period,
start: start,
end: end
};
return this._public('returnChartData', parameters, callback);
},
returnCurrencies: function (callback) {
return this._public('returnCurrencies', callback);
},
returnLoanOrders: function (currency, callback) {
return this._public('returnLoanOrders', { currency: currency }, callback);
},
returnTradeHistory: function (currencyA, currencyB, start, end, callback) {
if (arguments.length < 5) {
callback = start;
start = Date.now() / 1000 - 60 * 60;
end = Date.now() / 1000 + 60 * 60; // Some buffer in case of client/server time out of sync.
}
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
start: start,
end: end
};
return this._public('returnTradeHistory', parameters, callback);
},
/////
// PRIVATE METHODS
returnBalances: function (callback) {
return this._private('returnBalances', {}, callback);
},
returnCompleteBalances: function (account, callback) {
var parameters = {};
if (typeof account === 'function') {
callback = account;
}
else if (typeof account === 'string' && !!account) {
parameters.account = account;
}
return this._private('returnCompleteBalances', parameters, callback);
},
returnDepositAddresses: function (callback) {
return this._private('returnDepositAddresses', {}, callback);
},
generateNewAddress: function (currency, callback) {
return this._private('generateNewAddress', { currency: currency }, callback);
},
returnDepositsWithdrawals: function (start, end, callback) {
return this._private('returnDepositsWithdrawals', { start: start, end: end }, callback);
},
// can be called with `returnOpenOrders('all', callback)`
returnOpenOrders: function (currencyA, currencyB, callback) {
var currencyPair;
if (typeof currencyB === 'function') {
currencyPair = currencyA;
callback = currencyB;
currencyB = null;
}
else {
currencyPair = joinCurrencies(currencyA, currencyB);
}
var parameters = {
currencyPair: currencyPair
};
return this._private('returnOpenOrders', parameters, callback);
},
returnOrderTrades: function (orderNumber, callback) {
var parameters = {
orderNumber: orderNumber
};
return this._private('returnOrderTrades', parameters, callback);
},
buy: function (currencyA, currencyB, rate, amount, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
rate: rate,
amount: amount
};
return this._private('buy', parameters, callback);
},
sell: function (currencyA, currencyB, rate, amount, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
rate: rate,
amount: amount
};
return this._private('sell', parameters, callback);
},
cancelOrder: function (currencyA, currencyB, orderNumber, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
orderNumber: orderNumber
};
return this._private('cancelOrder', parameters, callback);
},
moveOrder: function (orderNumber, rate, amount, callback) {
var parameters = {
orderNumber: orderNumber,
rate: rate,
amount: amount ? amount : null
};
return this._private('moveOrder', parameters, callback);
},
withdraw: function (currency, amount, address, callback) {
var parameters = {
currency: currency,
amount: amount,
address: address
};
return this._private('withdraw', parameters, callback);
},
returnFeeInfo: function (callback) {
return this._private('returnFeeInfo', {}, callback);
},
returnAvailableAccountBalances: function (account, callback) {
var parameters = {};
if (typeof account === 'function') {
callback = account;
}
else if (typeof account === 'string' && !!account) {
parameters.account = account;
}
return this._private('returnAvailableAccountBalances', parameters, callback);
},
returnTradableBalances: function (callback) {
return this._private('returnTradableBalances', {}, callback);
},
transferBalance: function (currency, amount, fromAccount, toAccount, callback) {
var parameters = {
currency: currency,
amount: amount,
fromAccount: fromAccount,
toAccount: toAccount
};
return this._private('transferBalance', parameters, callback);
},
returnMarginAccountSummary: function (callback) {
return this._private('returnMarginAccountSummary', {}, callback);
},
marginBuy: function (currencyA, currencyB, rate, amount, lendingRate, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
rate: rate,
amount: amount,
lendingRate: lendingRate ? lendingRate : null
};
return this._private('marginBuy', parameters, callback);
},
marginSell: function (currencyA, currencyB, rate, amount, lendingRate, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB),
rate: rate,
amount: amount,
lendingRate: lendingRate ? lendingRate : null
};
return this._private('marginSell', parameters, callback);
},
getMarginPosition: function (currencyA, currencyB, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB)
};
return this._private('getMarginPosition', parameters, callback);
},
closeMarginPosition: function (currencyA, currencyB, callback) {
var parameters = {
currencyPair: joinCurrencies(currencyA, currencyB)
};
return this._private('closeMarginPosition', parameters, callback);
},
createLoanOffer: function (currency, amount, duration, autoRenew, lendingRate, callback) {
var parameters = {
currency: currency,
amount: amount,
duration: duration,
autoRenew: autoRenew,
lendingRate: lendingRate
};
return this._private('createLoanOffer', parameters, callback);
},
cancelLoanOffer: function (orderNumber, callback) {
var parameters = {
orderNumber: orderNumber
};
return this._private('cancelLoanOffer', parameters, callback);
},
returnOpenLoanOffers: function (callback) {
return this._private('returnOpenLoanOffers', {}, callback);
},
returnActiveLoans: function (callback) {
return this._private('returnActiveLoans', {}, callback);
},
returnLendingHistory: function (start, end, limit, callback) {
var parameters = {
start: start,
end: end,
limit: limit
};
return this._private('returnLendingHistory', parameters, callback);
},
toggleAutoRenew: function (orderNumber, callback) {
return this._private('toggleAutoRenew', { orderNumber: orderNumber }, callback);
}
};
// Backwards Compatibility
Poloniex.prototype.getTicker = Poloniex.prototype.returnTicker;
Poloniex.prototype.get24hVolume = Poloniex.prototype.return24hVolume;
Poloniex.prototype.getOrderBook = Poloniex.prototype.returnOrderBook;
Poloniex.prototype.getTradeHistory = Poloniex.prototype.returnChartData;
Poloniex.prototype.myBalances = Poloniex.prototype.returnBalances;
Poloniex.prototype.myOpenOrders = Poloniex.prototype.returnOpenOrders;
Poloniex.prototype.myTradeHistory = Poloniex.prototype.returnTradeHistory;
return Poloniex;
})();
-406
View File
@@ -1,406 +0,0 @@
exports.newAPIClient = function newAPIClient(keyVaultAPI) {
/*
/* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications.
/* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one.
*/
const FULL_LOG = true;
const LOG_FILE_CONTENT = true;
const MODULE_NAME = "poloniexClient";
const retry = require('../exchangeUtils').retry;
const includes = require('../exchangeUtils').includes;
const _ = require('lodash');
const Poloniex = require("./poloniex");
const exchangeProperties = require('./poloniexProperties.json');
const recoverableErrors = [
'SOCKETTIMEDOUT',
'TIMEDOUT',
'CONNRESET',
'CONNREFUSED',
'NOTFOUND',
'429',
'522',
'504',
'503',
'500',
'502',
'Empty response',
'Please try again in a few minutes.',
'Nonce must be greater than',
'Internal error. Please try again.',
'Connection timed out. Please try again.',
'ENOTFOUND',
'ECONNREFUSED',
'CONNREFUSED',
'NOTFOUND',
'ESOCKETTIMEDOUT',
'ECONNRESET',
'Connection timed out',
'Connection Error',
'Order not found, or you are not the person who placed it.',
'ETIMEDOUT'
];
let API = new Poloniex(keyVaultAPI);
let thisObject = {
getTicker: getTicker,
getOpenPositions: getOpenPositions,
getExecutedTrades: getExecutedTrades,
buy: buy,
sell: sell,
movePosition: movePosition,
getPublicTradeHistory: getPublicTradeHistory,
getExchangeProperties: getExchangeProperties,
isValidLot: isValidLot
};
return thisObject;
function joinCurrencies(currencyA, currencyB) {
// If only one arg, then return the first
if (typeof currencyB !== 'string') {
return currencyA;
}
return currencyA + '_' + currencyB;
}
/*
* Returns the properties for this exchange
*/
function getExchangeProperties() {
return exchangeProperties;
}
/*
* Returns the price for a given pair of assets.
* The object returned is an array of trades:
* ticker = {
* bid, Number
* ask, Number
* last Number
* };
*/
function getTicker(pMarket, callBack) {
const handle = (err, response) => {
let ticker;
let market = joinCurrencies(pMarket.assetA, pMarket.assetB);
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
ticker = {
bid: Number(response[market].highestBid),
ask: Number(response[market].lowestAsk),
last: Number(response[market].last)
};
}
callBack(err, ticker);
};
const fetch = next => API.getTicker(analizeResponse(next));
retry(null, fetch, handle);
}
/*
* Returns the open positions ath the exchange for a given market and user account.
* The object returned is an array of positions:
* position = {
* id,
* type,
* rate, Number
* amountA, Number
* amountB, Number
* fee, (not required) Number
* datetime
* };
*/
function getOpenPositions(pMarket, callBack) {
try {
if (CONSOLE_LOG === true) { console.log("[INFO] poloniexClient -> getOpenPositions -> Entering function."); }
const handle = (err, response) => {
let exchangePositions = [];
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
for (let i = 0; i < response.length; i++) {
let openPosition = {
id: response[i].orderNumber,
type: response[i].type,
rate: Number(response[i].rate),
amountA: Number(response[i].total),
amountB: Number(response[i].amount),
date: (new Date(response[i].time)).valueOf()
};
exchangePositions.push(openPosition);
}
}
callBack(err, exchangePositions);
};
const fetch = next => API.returnOpenOrders(pMarket.assetA, pMarket.assetB, analizeResponse(next));
retry(null, fetch, handle);
} catch (err) {
console.log("[ERROR] poloniexClient -> getOpenPositions -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Returns the trades for a given order number.
* The object returned is an array of positions:
* position = {
* id,
* type,
* rate, Number
* amountA, Number
* amountB, Number
* fee, Number
* datetime
* };
*/
function getExecutedTrades(pPositionId, callBack) {
try {
if (CONSOLE_LOG === true) { console.log("[INFO] poloniexClient -> getExecutedTrades -> Entering function."); }
const handle = (err, response) => {
let trades = [];
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
for (let i = 0; i < response.length; i++) {
let trade = {
id: response[i].tradeID,
type: response[i].type,
rate: Number(response[i].rate),
amountA: Number(response[i].total),
amountB: Number(response[i].amount),
fee: Number(response[i].fee),
date: (new Date(response[i].date)).valueOf()
}
trades.push(trade);
}
} else if (err.result === global.CUSTOM_OK_RESPONSE.result) {
// No trades found at the exchange for the position, but returning empy trades object.
err = global.DEFAULT_OK_RESPONSE;
}
callBack(err, trades);
};
const fetch = next => API.returnOrderTrades(pPositionId, analizeResponse(next));
retry(null, fetch, handle);
} catch (err) {
console.log("[ERROR] poloniexClient -> getExecutedTrades -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Creates a new buy order.
* The orderNumber is returned. String
*/
function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) {
try {
if (CONSOLE_LOG === true) { console.log("[INFO] poloniexClient -> buy -> Entering function."); }
const handle = (err, response) => {
let orderNumber;
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
orderNumber = response.orderNumber;
}
callBack(err, orderNumber);
};
const fetch = next => API.buy(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next));
retry(null, fetch, handle);
} catch (err) {
console.log("[ERROR] poloniexClient -> buy -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Creates a new sell order.
* The orderNumber is returned. String
*/
function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) {
try {
if (CONSOLE_LOG === true) { console.log("[INFO] poloniexClient -> sell -> Entering function."); }
const handle = (err, response) => {
let orderNumber;
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
orderNumber = response.orderNumber;
}
callBack(err, orderNumber);
};
const fetch = next => API.sell(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next));
retry(null, fetch, handle);
} catch (err) {
console.log("[ERROR] poloniexClient -> sell -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Move an existing position to the new rate.
* The orderNumber is returned. String
*/
function movePosition(pPosition, pNewRate, pNewAmountB, callBack) {
try {
if (CONSOLE_LOG === true) { console.log("[INFO] poloniexClient -> movePosition -> Entering function."); }
const handle = (err, response) => {
let orderNumber;
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
orderNumber = response.orderNumber;
}
callBack(err, orderNumber);
};
const fetch = next => API.moveOrder(pPosition.id, pNewRate, pNewAmountB, analizeResponse(next));
retry(null, fetch, handle);
} catch (err) {
console.log("[ERROR] poloniexClient -> movePosition -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
/*
* Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId.
* It's possible that the exchange doesn't support this method.
* The object returned is an array of trades:
* trade = {
* tradeID, String
* globalTradeID, String
* type, String
* rate, Number
* amountA, Number
* amountB, Number
* date Date
* };
*/
function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) {
try {
if (CONSOLE_LOG === true) { console.log("[INFO] poloniexClient -> getPublicTradeHistory -> Entering function."); }
const handle = (err, response) => {
let trades = [];
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
for (let i = 0; i < response.length; i++) {
let trade = {
tradeID: response[i].tradeID,
globalTradeID: response[i].globalTradeID,
type: response[i].type,
rate: Number(response[i].rate),
total: Number(response[i].total),
amount: Number(response[i].amount),
date: new Date(response[i].date)
}
trades.push(trade);
}
}
callBack(err, trades);
};
const fetch = next => API.returnTradeHistory(assetA, assetB, startTime, endTime, analizeResponse(next));
retry(null, fetch, handle);
} catch (err) {
console.log("[ERROR] poloniexClient -> getPublicTradeHistory -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function isValidLot(price, amount) {
return amount * price >= 0.0001;
}
function analizeResponse(callBack) {
return (exchangeErr, exchangeResponse) => {
let error;
/* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */
let stringExchangeErr = JSON.stringify(exchangeErr);
let stringExchangeResponse = JSON.stringify(exchangeResponse);
try {
if (FULL_LOG === true) { console.log("[INFO] poloniexClient -> analizeResponse -> exchangeErr = " + stringExchangeErr); }
if (FULL_LOG === true) { console.log("[INFO] poloniexClient -> analizeResponse -> exchangeResponse = " + stringExchangeResponse); }
if (exchangeErr) {
error = global.DEFAULT_FAIL_RESPONSE;
if (includes(exchangeErr.code, recoverableErrors)) {
error.notFatal = true;
}
} else if (!exchangeResponse || exchangeResponse === undefined) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: 'Empty response',
notFatal: true
};
} else if (includes(exchangeResponse.error, ['Please complete the security check to proceed.'])) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: 'The IP has been flagged by CloudFlare.'
};
} else if (includes(exchangeResponse.error, ['<!DOCTYPE html>'])) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: exchangeResponse
};
} else if (includes(exchangeResponse.error, ['Not enough'])) {
error = {
result: global.DEFAULT_RETRY_RESPONSE.result,
message: exchangeResponse.error
};
} else if (includes(exchangeResponse.error, ['Order not found, or you are not the person who placed it.'])) {
error = {
result: global.CUSTOM_OK_RESPONSE.result,
message: exchangeResponse.error
};
} else if (exchangeResponse.error) {
error = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: exchangeResponse.error
};
}
return callBack(error, exchangeResponse);
} catch (err) {
console.log("[ERROR] poloniexClient -> analizeResponse -> err.message = " + err.message);
return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse);
}
}
}
}
File diff suppressed because it is too large. Load diff
-100
View File
@@ -1,100 +0,0 @@
// generic low level reusuable utils for interacting with exchanges.
const retry = require('retry');
const _ = require('lodash');
const retryInstance = (options, checkFn, callback) => {
if(!options) {
options = {
retries: 100,
factor: 1.2,
minTimeout: 1 * 1000,
maxTimeout: 4 * 1000
};
}
let attempt = 0;
const operation = retry.operation(options);
operation.attempt(function(currentAttempt) {
checkFn((err, result) => {
if (!err) {
return callback(global.DEFAULT_OK_RESPONSE, result);
} else {
if (err.result === global.CUSTOM_OK_RESPONSE.result) {
return callback(err, result);
}
}
let maxAttempts = err.retry;
if(maxAttempts === true)
maxAttempts = 10;
if(err.retry && attempt++ < maxAttempts) {
return operation.retry(err);
}
if(err.notFatal) {
if(err.backoffDelay) {
return setTimeout(() => operation.retry(err), err.backoffDelay);
}
return operation.retry(err);
}
callback(err, result);
});
});
}
const isValidOrder = ({api, market, amount, price}) => {
let reason = false;
// Check amount
if(amount < market.minimalOrder.amount) {
reason = 'Amount is too small';
}
// Some exchanges have restrictions on prices
if(
_.isFunction(api.isValidPrice) &&
!api.isValidPrice(price)
) {
reason = 'Price is not valid';
}
if(
_.isFunction(api.isValidLot) &&
!api.isValidLot(price, amount)
) {
reason = 'Lot size is too small';
}
return {
reason,
valid: !reason
}
}
const includes = function(str, list) {
if (!_.isString(str))
return false;
return _.some(list, item => str.includes(item));
}
const getMarketConfig = function(exchangeProperties) {
return _.find(exchangeProperties.markets, (p) => {
return _.first(p.pair) === global.MARKET.assetA.toUpperCase() &&
_.last(p.pair) === global.MARKET.assetB.toUpperCase();
});
}
module.exports = {
retry: retryInstance,
includes: includes,
isValidOrder,
getMarketConfig
}
+24
View File
@@ -0,0 +1,24 @@
version: '3'
services:
node:
image: aaweb-dev:v1
build:
context: .
dockerfile: ./Dockerfile.prod
env_file: ./.env
container_name: aaweb
tty: true
stdin_open: true
volumes:
- ./:/var/www/app
- /var/www/app/node_modules
working_dir: /var/www/app
restart: always
command: node server
expose:
- 4101
network_mode: webproxy
networks:
default:
external:
name: webproxy
+11 -7
View File
@@ -8,15 +8,15 @@
<title>Superalgos</title>
<script src="https://unpkg.com/apollo-client-browser@1.7.0"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript" src="Scripts/require.js"></script>
<script type="text/javascript" src="Scripts/AppPreLoader.js"></script>
<link href="https://fonts.googleapis.com/css?family=Saira" rel="stylesheet">
</head>
<body id="body" style="margin: 0px; padding: 0px; border: 0px; overflow:hidden;" onresize="window.canvasApp.eventHandler.raiseEvent('Browser Resized');" onload="
window.canvasApp = {
version: '1.0.0', // This is used to avoid catching problems at the browser level.
<body id="body" style="margin: 0px; padding: 0px; border: 0px; " onresize="window.canvasApp.eventHandler.raiseEvent('Browser Resized');" onload="
window.canvasApp={
version: '1.0.0' , // This is used to avoid catching problems at the browser level.
sessionToken: '',
executingAt: 'Master App',
visible: true,
@@ -28,11 +28,15 @@
context: {}
};
loadAdvancedAlgosPlatform();
loadAdvancedAlgosPlatform();
">
<div id="masterApp"></div>
<div id="canvasApp"></div>
<div id="masterApp"></div>
<div id="canvasApp"></div>
<div id="textAreaDiv"></div>
<div id="inputDiv"></div>
</body>
</html>
+112 -1112
View File
File diff suppressed because it is too large. Load diff
+8 -9
View File
@@ -1,26 +1,25 @@
{
"name": "AAWeb",
"version": "0.0.0",
"description": "",
"name": "@superalgos/saweb",
"version": "0.1.0",
"description": "Superalgos web interface.",
"main": "server.js",
"author": {
"name": "Luis-Fernando-Molina"
"author": "Superalgos, ltd.",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/Superalgos/AAWeb.git"
},
"dependencies": {
"@octokit/rest": "^14.0.9",
"@superalgos/mqservice": "0.0.12",
"atob": "^2.1.2",
"axios": "^0.18.0",
"azure-storage": "^2.10.2",
"dotenv": "^6.2.0",
"graphql": "^14.2.0",
"graphql-client": "^2.0.1",
"json-beautify": "^1.0.1",
"lodash": "^4.17.11",
"minio": "^7.0.5",
"nonce": "^1.0.4",
"request": "^2.88.0",
"retry": "^0.12.0",
"winston": "^3.2.1"
}
}
+28 -142
View File
@@ -131,7 +131,7 @@ function initialize () {
}
}
}
}
}
}
@@ -198,7 +198,7 @@ function onBrowserRequest (request, response) {
processPost(request, response, onPostReceived)
function onPostReceived(pData) {
let request = JSON.parse(pData);
storage.readData(undefined, request.path, request.conatinerName, false, onReady)
@@ -427,22 +427,6 @@ function onBrowserRequest (request, response) {
}
break
case 'Exchange': // This means the Exchange folder.
{
let filePath = requestParameters[2]
if (requestParameters[3] !== undefined) {
filePath = filePath + '/' + requestParameters[3]
}
if (requestParameters[4] !== undefined) {
filePath = filePath + '/' + requestParameters[4]
}
respondWithFile(serverConfig.pathToCanvasApp + '/Exchange/' + filePath, response)
}
break
case 'Images': // This means the Scripts folder.
{
let path = './Images/' + requestParameters[2]
@@ -471,9 +455,9 @@ function onBrowserRequest (request, response) {
}
break
case 'BottomSpace': // This means the BottomSpace folder.
case 'CockpitSpace': // This means the CockpitSpace folder.
{
respondWithFile(serverConfig.pathToCanvasApp + '/BottomSpace/' + requestParameters[2], response)
respondWithFile(serverConfig.pathToCanvasApp + '/CockpitSpace/' + requestParameters[2], response)
}
break
@@ -483,6 +467,24 @@ function onBrowserRequest (request, response) {
}
break
case 'StrategySpace': // This means the StrategySpace folder.
{
respondWithFile(serverConfig.pathToCanvasApp + '/StrategySpace/' + requestParameters[2], response)
}
break
case 'ControlsToolBox': // This means the StrategySpace folder.
{
respondWithFile(serverConfig.pathToCanvasApp + '/ControlsToolBox/' + requestParameters[2], response)
}
break
case 'Utilities': // This means the StrategySpace folder.
{
respondWithFile(serverConfig.pathToCanvasApp + '/Utilities/' + requestParameters[2], response)
}
break
case 'AABrowserAPI': // This means the Scripts folder.
{
switch (requestParameters[2]) {
@@ -696,128 +698,6 @@ function onBrowserRequest (request, response) {
}
break
case 'ExchangeAPI': // This is trying to access this library functionality from the broser.
{
/* We are going to let access the exchange only to authenticated users, that measn that we need the a valid session token. */
let authToken = requestParameters[3]
if (authToken !== undefined) {
global.CURRENT_EXECUTION_AT = "Browser"
global.GATEWAY_ENDPOINT = serverConfig.masterAppServerURL
global.MARKET = {
assetA: "USDT",
assetB: "BTC"
};
global.LOG_CONTROL = {
"Exchange API": {
logInfo: true,
logWarnings: false,
logErrors: true,
logContent: false,
intensiveLogging: false
}
}
let logger = {
write: function (moduleName, message) {
console.log(moduleName + " " + message);
}
}
const EXCHANGE_API = require('./Server/Exchange/ExchangeAPI');
let exchangeAPI = EXCHANGE_API.newExchangeAPI(logger, authToken);
exchangeAPI.initialize(onInizialized);
function onInizialized(err) {
if (CONSOLE_LOG === true) { console.log("[INFO] server -> onBrowserRequest -> ExchangeAPI -> onInizialized -> Entering function."); }
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
if (CONSOLE_LOG === true) { console.log("[INFO] server -> onBrowserRequest -> ExchangeAPI -> onInizialized -> Execution finished well."); }
callExchangeAPIMethod();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
console.log("[ERROR] server -> onBrowserRequest -> ExchangeAPI -> onInizialized -> Retry Later. Requesting Execution Retry.");
respondWithContent("", response);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
console.log("[ERROR] server -> onBrowserRequest -> ExchangeAPI -> onInizialized -> Operation Failed. Aborting the process.");
respondWithContent("", response);
return;
}
}
}
function callExchangeAPIMethod() {
switch (requestParameters[2]) {
case "getTicker": {
exchangeAPI.getTicker(global.MARKET, onExchangeResponse);
break;
}
case "getOpenPositions": {
exchangeAPI.getOpenPositions(global.MARKET, onExchangeResponse);
break;
}
case "getExecutedTrades": {
exchangeAPI.getExecutedTrades(requestParameters[4], onExchangeResponse);
break;
}
case "putPosition": {
exchangeAPI.putPosition(global.MARKET, requestParameters[4], requestParameters[5], requestParameters[6], requestParameters[7], onExchangeResponse);
break;
}
case "movePosition": {
exchangeAPI.moveOrder(requestParameters[4], requestParameters[5], requestParameters[6], onExchangeResponse);
break;
}
case "getPublicTradeHistory": {
exchangeAPI.getPublicTradeHistory(global.MARKET, requestParameters[4], requestParameters[5], requestParameters[6], onExchangeResponse);
break;
}
case "initialize": {
onExchangeResponse(global.DEFAULT_OK_RESPONSE);
break;
}
}
}
function onExchangeResponse(err, exchangeResponse) {
/* Delete these secrets before they get logged. */
requestParameters[4] = "";
if (err.result === global.DEFAULT_OK_RESPONSE.result)
respondWithContent(JSON.stringify(exchangeResponse), response);
else
respondWithContent(JSON.stringify(err), response);
}
return;
} else {
let customResponse = {
result: global.CUSTOM_FAIL_RESPONSE.result,
message: "You are not logged in."
};
respondWithContent(JSON.stringify(customResponse), response);
}
}
break
case 'AACloud': // This means the cloud folder.
{
let filePath = requestParameters[2]
@@ -976,6 +856,12 @@ function onBrowserRequest (request, response) {
}
break
case 'ChartsSpace':
{
respondWithFile(serverConfig.pathToCanvasApp + '/' + requestParameters[1] + '/' + requestParameters[2], response)
}
break
default:
{
homePage()