Adding support for multiple bot execution
This commit is contained in:
1 parent
709a6cb770
commit
2cda4ad606
14 files changed
+74
-81
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@superalgos/operations-client",
|
||||
"version": "0.0.11",
|
||||
"version": "0.0.12",
|
||||
"description": "Superalgos Operations client-side web app",
|
||||
"main": "src/index.js",
|
||||
"dependencies": {
|
||||
|
||||
@@ -29,5 +29,6 @@ export const clone = gql`
|
||||
botName
|
||||
botAvatar
|
||||
teamAvatar
|
||||
processName
|
||||
}
|
||||
`;
|
||||
@@ -1,21 +1,18 @@
|
||||
const types = [ 'Live', 'Competition', 'Backtest' ]
|
||||
const availableMonths = ["January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December"]
|
||||
|
||||
const startModes = [
|
||||
{
|
||||
name: 'All Months',
|
||||
value: 'allMonths'
|
||||
},
|
||||
{
|
||||
name: 'One Month',
|
||||
value: 'oneMonth'
|
||||
},
|
||||
{
|
||||
name: 'No Time',
|
||||
value: 'noTime'
|
||||
}
|
||||
]
|
||||
const tradingStartModes ={
|
||||
live: "Live",
|
||||
competition: "Competition",
|
||||
backtest: "Backtest"
|
||||
}
|
||||
|
||||
const indicatorStartModes = {
|
||||
allMonths: "All Months",
|
||||
oneMonth: "One Month",
|
||||
noTime: "No Time"
|
||||
}
|
||||
|
||||
const exchanges = [
|
||||
{
|
||||
id: '1',
|
||||
@@ -25,4 +22,4 @@ const exchanges = [
|
||||
|
||||
|
||||
|
||||
export { types, exchanges, startModes, availableMonths }
|
||||
export { tradingStartModes, exchanges, indicatorStartModes, availableMonths }
|
||||
@@ -9,7 +9,7 @@ import { withStyles } from '@material-ui/core/styles'
|
||||
import classNames from 'classnames'
|
||||
import styles from './styles'
|
||||
|
||||
import { types, startModes, availableMonths, processNames } from '../../../GraphQL/models'
|
||||
import { tradingStartModes, indicatorStartModes, availableMonths, processNames } from '../../../GraphQL/models'
|
||||
import { isDefined, getIndicatorYears } from '../../../utils'
|
||||
|
||||
import {
|
||||
@@ -176,9 +176,9 @@ class AddClone extends Component {
|
||||
error={this.state.modeError}
|
||||
fullWidth
|
||||
>
|
||||
{types.map(option => (
|
||||
{Object.keys(tradingStartModes).map(option => (
|
||||
<MenuItem key={option} value={option}>
|
||||
{option}
|
||||
{tradingStartModes[option]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
@@ -290,9 +290,9 @@ class AddClone extends Component {
|
||||
error={this.state.modeError}
|
||||
fullWidth
|
||||
>
|
||||
{startModes.map(option => (
|
||||
<MenuItem key={option.value} value={option.value}>
|
||||
{option.name}
|
||||
{Object.keys(indicatorStartModes).map(option => (
|
||||
<MenuItem key={option} value={option}>
|
||||
{indicatorStartModes[option]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
@@ -449,7 +449,6 @@ class AddClone extends Component {
|
||||
botId: this.state.selectedBot.id,
|
||||
mode: this.state.mode,
|
||||
resumeExecution: this.state.resumeExecution,
|
||||
runAsTeam: this.state.runAsTeam,
|
||||
botType: this.getBotTypeFromKind(this.state.selectedBot.kind)
|
||||
}
|
||||
}
|
||||
@@ -460,11 +459,15 @@ class AddClone extends Component {
|
||||
variables.clone.waitTime = this.state.waitTime
|
||||
}
|
||||
|
||||
if(this.state.selectedBot.kind !== "TRADER"){
|
||||
if(this.state.selectedBot.kind === "TRADER"){
|
||||
variables.clone.runAsTeam = this.state.runAsTeam
|
||||
variables.clone.processName = 'Trading-Process'
|
||||
} else {
|
||||
variables.clone.processName = this.state.processName
|
||||
variables.clone.startYear = this.state.startYear
|
||||
variables.clone.endYear = this.state.endYear
|
||||
variables.clone.month = this.state.month
|
||||
variables.clone.runAsTeam = true
|
||||
}
|
||||
|
||||
return this.props.addCloneMutation({
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
|
||||
import { tradingStartModes, indicatorStartModes } from '../../../GraphQL/models'
|
||||
import { isDefined, toLocalTime } from '../../../utils'
|
||||
import classNames from 'classnames'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
@@ -45,7 +46,9 @@ class ListClones extends Component {
|
||||
<Typography className={classes.heading}>{clone.botName}</Typography>
|
||||
</div>
|
||||
<div className={classes.heading}>
|
||||
<Typography className={classes.heading}>{clone.mode}</Typography>
|
||||
<Typography className={classes.heading}>
|
||||
{ clone.processName } / { clone.botType === 'TRADER' ? tradingStartModes[clone.mode] : indicatorStartModes[clone.mode] }
|
||||
</Typography>
|
||||
</div>
|
||||
</ExpansionPanelSummary>
|
||||
<Divider />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const LIVE = 'Live'
|
||||
export const BACKTEST = 'Backtest'
|
||||
export const COMPETITION = 'Competition'
|
||||
export const LIVE = 'live'
|
||||
export const BACKTEST = 'backtest'
|
||||
export const COMPETITION = 'competition'
|
||||
export const ALL_MONTHS = 'allMonths'
|
||||
export const ONE_MONTH = 'oneMonth'
|
||||
export const NO_TIME = 'noTime'
|
||||
|
||||
@@ -4,15 +4,16 @@ import { KubernateError } from '../errors'
|
||||
import { Client, config } from 'kubernetes-client'
|
||||
// Get base Deployment config
|
||||
import deploymentManifest from '../config/clone-deployment.json'
|
||||
import { BACKTEST} from '../enums/CloneMode';
|
||||
import { BACKTEST, NO_TIME } from '../enums/CloneMode'
|
||||
import { TRADER, INDICATOR, EXTRACTION } from '../enums/BotTypes'
|
||||
|
||||
const createClone = async (clone) => {
|
||||
try {
|
||||
logger.debug("createClone %s", clone.cloneName)
|
||||
logger.debug("createClone %s", clone.id)
|
||||
const client = new Client({config: config.fromKubeconfig(), version: '1.9'})
|
||||
|
||||
// Make changes to base deployment config
|
||||
deploymentManifest.metadata.name = clone.cloneName
|
||||
deploymentManifest.metadata.name = clone.id
|
||||
|
||||
logger.debug("createClone Environment and Auth Configuration.")
|
||||
let env = []
|
||||
@@ -68,7 +69,7 @@ const createClone = async (clone) => {
|
||||
})
|
||||
env.push({
|
||||
"name": "START_MODE",
|
||||
"value": clone.mode.toLowerCase()
|
||||
"value": clone.mode
|
||||
})
|
||||
env.push({
|
||||
"name": "RUN_AS_TEAM",
|
||||
@@ -78,13 +79,13 @@ const createClone = async (clone) => {
|
||||
"name": "USER_LOGGED_IN",
|
||||
"value": clone.userLoggedIn
|
||||
})
|
||||
env.push({
|
||||
"name": "PROCESS",
|
||||
"value": clone.processName
|
||||
})
|
||||
|
||||
logger.debug("createClone Trading Configuration.")
|
||||
if(clone.botType === 'Trading'){
|
||||
env.push({
|
||||
"name": "PROCESS",
|
||||
"value": 'Trading-Process'
|
||||
})
|
||||
if(clone.botType === TRADER ){
|
||||
env.push({
|
||||
"name": "RESUME_EXECUTION",
|
||||
"value": clone.resumeExecution.toString()
|
||||
@@ -104,27 +105,25 @@ const createClone = async (clone) => {
|
||||
"value": clone.waitTime.toString()
|
||||
})
|
||||
}
|
||||
} else if(clone.botType === 'Indicator' || clone.botType === 'Extraction'){
|
||||
env.push({
|
||||
"name": "PROCESS",
|
||||
"value": clone.processName
|
||||
})
|
||||
env.push({
|
||||
"name": "MIN_YEAR",
|
||||
"value": isDefined(clone.startYear) ? clone.startYear.toString() : ''
|
||||
})
|
||||
env.push({
|
||||
"name": "MAX_YEAR",
|
||||
"value": isDefined(clone.endYear) ? clone.endYear.toString() : ''
|
||||
})
|
||||
env.push({
|
||||
"name": "MONTH",
|
||||
"value": isDefined(clone.month) ? clone.month.toString() : ''
|
||||
})
|
||||
env.push({
|
||||
"name": "INTERVAL",
|
||||
"value": isDefined(clone.interval) ? clone.interval.toString() : ''
|
||||
})
|
||||
} else if(clone.botType === INDICATOR || clone.botType === EXTRACTION ){
|
||||
if(clone.mode !== NO_TIME){
|
||||
env.push({
|
||||
"name": "MIN_YEAR",
|
||||
"value": isDefined(clone.startYear) ? clone.startYear.toString() : ''
|
||||
})
|
||||
env.push({
|
||||
"name": "MAX_YEAR",
|
||||
"value": isDefined(clone.endYear) ? clone.endYear.toString() : ''
|
||||
})
|
||||
env.push({
|
||||
"name": "MONTH",
|
||||
"value": isDefined(clone.month) ? clone.month.toString() : ''
|
||||
})
|
||||
env.push({
|
||||
"name": "INTERVAL",
|
||||
"value": isDefined(clone.interval) ? clone.interval.toString() : ''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deploymentManifest.spec.template.spec.containers[0].env = env
|
||||
|
||||
@@ -4,12 +4,12 @@ import { Client, config } from 'kubernetes-client'
|
||||
|
||||
const removeClone = async (clone) => {
|
||||
try {
|
||||
logger.debug("removeClone %s", clone.cloneName)
|
||||
logger.debug("removeClone %s", clone.id)
|
||||
const client = new Client({config: config.fromKubeconfig(), version: '1.9'})
|
||||
|
||||
let query = {
|
||||
"qs":{
|
||||
"labelSelector": "job-name=" + clone.cloneName
|
||||
"labelSelector": "job-name=" + clone.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,11 @@ const cloneSchema = new Schema({
|
||||
combinedProfitsA: Number,
|
||||
combinedProfitsB: Number,
|
||||
assetA: String,
|
||||
assetB: String
|
||||
assetB: String,
|
||||
processName: {
|
||||
type: String,
|
||||
required: true,
|
||||
}
|
||||
})
|
||||
|
||||
const Clone = mongoose.model('Clone', cloneSchema)
|
||||
|
||||
@@ -5,7 +5,6 @@ import { AutorizationError } from '../errors'
|
||||
const cloneDetails = async(authId, team, clone) => {
|
||||
logger.debug('Retrieving clone details.')
|
||||
|
||||
// TODO Pending improvement by authorization module
|
||||
if(!(authId === process.env.AACLOUD_ID || isAuthorized(team, authId))){
|
||||
logger.debug('User %s is not authorized to manage team %s.', authId, team.slug )
|
||||
throw new AutorizationError()
|
||||
@@ -17,7 +16,6 @@ const cloneDetails = async(authId, team, clone) => {
|
||||
clone.kind = selectedBot.kind
|
||||
clone.teamSlug = team.slug
|
||||
clone.botSlug = selectedBot.slug
|
||||
clone.cloneName = (clone.teamSlug + '-' + clone.botSlug + '-' + clone.mode).toLowerCase()
|
||||
clone.teamName = team.name
|
||||
clone.botName = selectedBot.name
|
||||
clone.botAvatar = selectedBot.avatar
|
||||
|
||||
@@ -35,20 +35,6 @@ const resolve = async(parent, { clone }, context) => {
|
||||
throw new WrongArgumentsError('The bot type selected is not valid.')
|
||||
}
|
||||
|
||||
let existingClone = await Clone.find(
|
||||
{
|
||||
authId: context.userId,
|
||||
mode: clone.mode,
|
||||
botId: clone.botId,
|
||||
active: true
|
||||
})
|
||||
|
||||
logger.debug('addClone -> Checking existing clone.')
|
||||
if(existingClone.length > 0){
|
||||
throw new OperationsError('You can only have one active clone by mode. Remove the'
|
||||
+ ' existing clone of type: ' + clone.mode + ' and try again.')
|
||||
}
|
||||
|
||||
try{
|
||||
let team = await teamQuery(context.authorization, clone.teamId)
|
||||
clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone)
|
||||
|
||||
@@ -30,11 +30,12 @@ const resolve = async(parent, args, context) => {
|
||||
}).sort({createDatetime: -1})
|
||||
|
||||
for (var i = 0; i < clones.length; i++) {
|
||||
logger.debug('List Clones -> clone: %j',clones[i] )
|
||||
let team = await teamQuery(context.authorization, clones[i].teamId)
|
||||
clones[i] = await cloneDetails(context.userId, team.data.data.teams_TeamById, clones[i])
|
||||
let state = await getCloneStatus(clones[i].cloneName)
|
||||
let state = await getCloneStatus(clones[i].id)
|
||||
clones[i].state = state.substring(1, state.length-1)
|
||||
let lastLogs = await getCloneLogs(clones[i].cloneName)
|
||||
let lastLogs = await getCloneLogs(clones[i].id)
|
||||
clones[i].lastLogs = lastLogs.substring(1, lastLogs.length-1)
|
||||
clones[i].botType = clones[i].kind // Only for listing we show the teams value
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ const CloneType = new GraphQLObjectType({
|
||||
createDatetime: {type: GraphQLInt},
|
||||
lastLogs: {type: GraphQLString},
|
||||
runAsTeam: {type: GraphQLBoolean},
|
||||
processName: { type: GraphQLString },
|
||||
summaryDate: {type: GraphQLInt},
|
||||
buyAverage: {type: GraphQLFloat},
|
||||
sellAverage: {type: GraphQLFloat},
|
||||
|
||||
@@ -22,7 +22,7 @@ const Type = new GraphQLInputObjectType({
|
||||
endYear: { type: GraphQLInt },
|
||||
month: { type: GraphQLInt },
|
||||
interval: { type: GraphQLInt },
|
||||
processName: { type: GraphQLString },
|
||||
processName: { type: new GraphQLNonNull(GraphQLString) },
|
||||
botType: { type: new GraphQLNonNull(GraphQLString) }
|
||||
})
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user