diff --git a/client/package-lock.json b/client/package-lock.json index a41a32819..60295d23c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,6 +1,6 @@ { "name": "@superalgos/operations-client", - "version": "0.0.17", + "version": "0.0.18", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/client/package.json b/client/package.json index 63204e01c..483789cf3 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@superalgos/operations-client", - "version": "0.0.18", + "version": "0.0.21", "description": "Superalgos Operations client-side web app", "main": "src/index.js", "dependencies": { diff --git a/client/src/GraphQL/models.js b/client/src/GraphQL/models.js index cd7e37973..0ce6667fc 100644 --- a/client/src/GraphQL/models.js +++ b/client/src/GraphQL/models.js @@ -1,5 +1,19 @@ -const availableMonths = ['January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December'] +const availableMonths = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' +] + +const availableTimePeriods = ["24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs", "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min"] const tradingStartModes = { live: 'Live', @@ -18,6 +32,14 @@ const indicatorStartModes = { noTime: 'No Time' } +const processNames = { + Daily: 'Multi-Period-Daily', + Market: 'Multi-Period-Market', + Min: "One-Min-Daily-Candles-Volumes", + Live: "Poloniex-Live-Trades", + HoleFixing: "Poloniex-Hole-Fixing" +} + const exchanges = [ { id: '1', @@ -25,4 +47,4 @@ const exchanges = [ } ] -export { tradingStartModes, tradingStartModesList, exchanges, indicatorStartModes, availableMonths } +export { tradingStartModes, tradingStartModesList, exchanges, indicatorStartModes, availableMonths, processNames, availableTimePeriods } diff --git a/client/src/views/Clone/Add/index.js b/client/src/views/Clone/Add/index.js index 4e52af534..dce62039f 100644 --- a/client/src/views/Clone/Add/index.js +++ b/client/src/views/Clone/Add/index.js @@ -6,7 +6,7 @@ import TopBar from '../../BannerTopBar' import { withStyles } from '@material-ui/core/styles' import classNames from 'classnames' import styles from './styles' -import { tradingStartModes, indicatorStartModes, availableMonths } from '../../../GraphQL/models' +import { tradingStartModes, indicatorStartModes, availableMonths, processNames, availableTimePeriods } from '../../../GraphQL/models' import { isDefined, getIndicatorYears } from '../../../utils' import { MenuItem, Button, TextField, FormControl, InputLabel, Input, Typography, @@ -43,6 +43,9 @@ class AddClone extends Component { month: 1, processName: '', + //TraderBot + timePeriod: '01-hs', + //Error handlers nameError: false, teamError: false, @@ -215,19 +218,6 @@ class AddClone extends Component { className={classNames(classes.form, classes.textField)} fullWidth /> - - - The Wait Time represent the number of miliseconds the bot will wait between executions. - - - this.setState({waitTime:e.target.value})} - fullWidth - /> } @@ -290,6 +280,27 @@ class AddClone extends Component { } + + + + The Time Period in which the bot will operate. + + + this.setState({timePeriod:e.target.value})} + fullWidth + > + {availableTimePeriods.map((option, index) => ( + + {option} + + ))} + + { false && @@ -320,6 +331,7 @@ class AddClone extends Component { || this.state.selectedBot.kind === "EXTRACTOR") && this.setState({processNameError:false})} error={this.state.processNameError} fullWidth - /> + > + {Object.keys(processNames).map(option => ( + + {processNames[option]} + + ))} + + {getIndicatorYears().map((option, index) => ( - + {option} ))} this.setState({month:e.target.value})} fullWidth > - {availableMonths.map(option => ( - + {availableMonths.map((option, index) => ( + {option} ))} @@ -506,6 +525,7 @@ class AddClone extends Component { if(this.state.selectedBot.kind === "TRADER"){ variables.clone.runAsTeam = this.state.runAsTeam variables.clone.processName = 'Trading-Process' + variables.clone.timePeriod = this.state.timePeriod if(this.state.mode === "backtest"){ variables.clone.beginDatetime = this.state.beginDatetime.valueOf() / 1000|0 variables.clone.endDatetime = this.state.endDatetime.valueOf() / 1000|0 diff --git a/server/src/kubernetes/createClone.js b/server/src/kubernetes/createClone.js index 83ac6af4e..57d6560cf 100644 --- a/server/src/kubernetes/createClone.js +++ b/server/src/kubernetes/createClone.js @@ -88,6 +88,11 @@ const createClone = async (clone) => { 'value': clone.resumeExecution.toString() }) + env.push({ + 'name': 'EXECUTION_PARAMETERS', + 'value': buildExecutionParameters(clone) + }) + if (clone.mode === BACKTEST) { env.push({ 'name': 'BEGIN_DATE_TIME', @@ -151,4 +156,36 @@ const createClone = async (clone) => { throw new KubernateError(err) } } + +function buildExecutionParameters(clone){ + let executionParameters = {} + executionParameters.timePeriod = clone.timePeriod + executionParameters.dataSet = datasetNames().get(clone.timePeriod) + return executionParameters +} + +function datasetNames(){ + let dataSetMap = new Map() + dataSetMap.set("24-hs","Multi-Period-Market") + dataSetMap.set("12-hs","Multi-Period-Market") + dataSetMap.set("08-hs","Multi-Period-Market") + dataSetMap.set("06-hs","Multi-Period-Market") + dataSetMap.set("04-hs","Multi-Period-Market") + dataSetMap.set("03-hs","Multi-Period-Market") + dataSetMap.set("02-hs","Multi-Period-Market") + dataSetMap.set("01-hs","Multi-Period-Market") + dataSetMap.set("45-min","Multi-Period-Daily") + dataSetMap.set("40-min","Multi-Period-Daily") + dataSetMap.set("30-min","Multi-Period-Daily") + dataSetMap.set("20-min","Multi-Period-Daily") + dataSetMap.set("15-min","Multi-Period-Daily") + dataSetMap.set("10-min","Multi-Period-Daily") + dataSetMap.set("05-min","Multi-Period-Daily") + dataSetMap.set("04-min","Multi-Period-Daily") + dataSetMap.set("03-min","Multi-Period-Daily") + dataSetMap.set("02-min","Multi-Period-Daily") + dataSetMap.set("01-min","Multi-Period-Daily") + return dataSetMap +} + export default createClone diff --git a/server/src/kubernetes/getClonePodLogs.js b/server/src/kubernetes/getClonePodLogs.js index 5367bfdd8..52c97230a 100644 --- a/server/src/kubernetes/getClonePodLogs.js +++ b/server/src/kubernetes/getClonePodLogs.js @@ -20,13 +20,18 @@ const getClonePodLogs = async (cloneName) => { 'tailLines': '20' } } - const logs = await client.api.v1.namespaces('default') - .pods(pod.body.items[0].metadata.name).log.get(queryLogs) - let logsArray = logs.body.split('\n') + if(pod.body.items[0] !== undefined){ + const logs = await client.api.v1.namespaces('default') + .pods(pod.body.items[0].metadata.name).log.get(queryLogs) + let logsArray = logs.body.split('\n') - logger.debug('getClonePodLogs on kubernates successful.') + logger.debug('getClonePodLogs on kubernates successful.') - return JSON.stringify(logsArray, null, 2) + return JSON.stringify(logsArray, null, 2) + } else { + logger.warn('getClonePodStatus pod not found %s: ', cloneName) + return "Logs not available." + } } catch (err) { throw new KubernateError(err) } diff --git a/server/src/kubernetes/getClonePodStatus.js b/server/src/kubernetes/getClonePodStatus.js index 957cf49ed..94412b09e 100644 --- a/server/src/kubernetes/getClonePodStatus.js +++ b/server/src/kubernetes/getClonePodStatus.js @@ -5,7 +5,7 @@ import { Client, config } from 'kubernetes-client' const getClonePodStatus = async (cloneName) => { try { logger.debug('getClonePodStatus on kubernates started. ') - const client = new Client({config: config.fromKubeconfig(), version: '1.9'}) + const client = new Client({ config: config.fromKubeconfig(), version: '1.9' }) let query = { 'qs': { @@ -15,14 +15,20 @@ const getClonePodStatus = async (cloneName) => { const pod = await client.api.v1.namespaces('default').pods.get(query) - let clonePodStatus = pod.body.items[0].status.containerStatuses[0].state + if (pod.body.items[0] !== undefined) { + let clonePodStatus = pod.body.items[0].status.containerStatuses[0].state - if (clonePodStatus.hasOwnProperty('terminated') - && clonePodStatus.terminated.hasOwnProperty('containerID')) { - delete clonePodStatus.terminated.containerID + if (clonePodStatus.hasOwnProperty('terminated') + && clonePodStatus.terminated.hasOwnProperty('containerID')) { + delete clonePodStatus.terminated.containerID + } + logger.debug('getClonePodStatus %s on kubernates successful', cloneName) + + return JSON.stringify(clonePodStatus, null, 2) + } else { + logger.warn('getClonePodStatus pod not found %s: ', cloneName) + return " Clone not found on the server. " } - logger.debug('getClonePodStatus %s on kubernates successful', cloneName) - return JSON.stringify(clonePodStatus, null, 2) } catch (err) { throw new KubernateError(err) } diff --git a/server/src/kubernetes/removeClone.js b/server/src/kubernetes/removeClone.js index 8bac6a3fa..54bb0c3c5 100644 --- a/server/src/kubernetes/removeClone.js +++ b/server/src/kubernetes/removeClone.js @@ -20,7 +20,7 @@ const removeClone = async (clone) => { logger.debug('removeClone %s on kubernates succesful', clone.id) } catch (err) { - throw new KubernateError(err) + logger.warn('removeClone %s on kubernates failed, the job was not found on the server.', clone.id) } } export default removeClone diff --git a/server/src/schema/mutations/AddCloneMutation.js b/server/src/schema/mutations/AddCloneMutation.js index 092ffe6e7..edaf47e4d 100644 --- a/server/src/schema/mutations/AddCloneMutation.js +++ b/server/src/schema/mutations/AddCloneMutation.js @@ -21,7 +21,7 @@ const args = { clone: { type: CloneInputType } } -const resolve = async(parent, { clone }, context) => { +const resolve = async (parent, { clone }, context) => { logger.debug('addClone -> Entering Fuction.') if (!context.userId) { @@ -36,7 +36,7 @@ const resolve = async(parent, { clone }, context) => { throw new WrongArgumentsError('The bot type selected is not valid.') } - if ( (clone.mode === LIVE || clone.mode === COMPETITION) && !isDefined(clone.keyId)) { + if ((clone.mode === LIVE || clone.mode === COMPETITION) && !isDefined(clone.keyId)) { throw new WrongArgumentsError('The key was not provided to run the clone.') } @@ -62,7 +62,7 @@ const resolve = async(parent, { clone }, context) => { } else { throw new AutorizationError() } - }else{ + } else { await createKubernetesClone(clone) } diff --git a/server/src/schema/types/input/Clone.js b/server/src/schema/types/input/Clone.js index 509ea9af5..3b106dafa 100644 --- a/server/src/schema/types/input/Clone.js +++ b/server/src/schema/types/input/Clone.js @@ -24,7 +24,8 @@ const Type = new GraphQLInputObjectType({ interval: { type: GraphQLInt }, processName: { type: new GraphQLNonNull(GraphQLString) }, botType: { type: new GraphQLNonNull(GraphQLString) }, - keyId: { type: GraphQLString } + keyId: { type: GraphQLString }, + timePeriod: { type: GraphQLString } }) })