Merge branch 'plugins-docs' of https://github.com/Superalgos/Superalgos into plugins-docs

This commit is contained in:
Chris committed 2021-08-23 09:52:02 +02:00
commit 23792bdc13
135 files changed
+20501 -13721

No files matched your search

+73
View File
@@ -0,0 +1,73 @@
exports.newMultiProject = function () {
let thisObject = {
initialize: initialize
}
return thisObject;
function initialize() {
/*
First thing is to load the project schema file.
*/
let PROJECTS_SCHEMA = require(global.env.PATH_TO_PROJECTS_REQUIRED + '/' + 'ProjectsSchema.json')
/*
Here we will setup the CL object, with all the
projects and modules that will have inside.
*/
global.CL = {
projects: {}
}
for (let i = 0; i < PROJECTS_SCHEMA.length; i++) {
let projectDefinition = PROJECTS_SCHEMA[i]
global.CL.projects[projectDefinition.propertyName] = {}
let projectInstance = global.CL.projects[projectDefinition.propertyName]
projectInstance.utilities = {}
projectInstance.globals = {}
projectInstance.functionLibraries = {}
projectInstance.taskModules = {}
projectInstance.processModules = {}
projectInstance.botModules = {}
if (projectDefinition.CL === undefined) { continue }
/* Set up Utilities of this Project */
if (projectDefinition.CL.utilities !== undefined) {
for (let j = 0; j < projectDefinition.CL.utilities.length; j++) {
let utilityDefinition = projectDefinition.CL.utilities[j]
let path = global.env.PATH_TO_PROJECTS_REQUIRED + '/' + projectDefinition.name + '/' + 'CL' + '/' + 'Utilities' + '/' + utilityDefinition.fileName
let requiredObject = require(path)
let requiredFunction = requiredObject[utilityDefinition.functionName]
projectInstance.utilities[utilityDefinition.propertyName] = requiredFunction.call()
}
}
/* Set up Globals of this Project */
if (projectDefinition.CL.globals !== undefined) {
for (let j = 0; j < projectDefinition.CL.globals.length; j++) {
let globalDefinition = projectDefinition.CL.globals[j]
let path = global.env.PATH_TO_PROJECTS_REQUIRED + '/' + projectDefinition.name + '/' + 'CL' + '/' + 'Globals' + '/' + globalDefinition.fileName
let requiredObject = require(path)
let requiredFunction = requiredObject[globalDefinition.functionName]
projectInstance.globals[globalDefinition.propertyName] = requiredFunction.call()
}
}
/* Set up Function Libraries of this Project */
if (projectDefinition.CL.functionLibraries !== undefined) {
for (let j = 0; j < projectDefinition.CL.functionLibraries.length; j++) {
let functionLibraryDefinition = projectDefinition.CL.functionLibraries[j]
let path = global.env.PATH_TO_PROJECTS_REQUIRED + '/' + projectDefinition.name + '/' + 'CL' + '/' + 'Function-Libraries' + '/' + functionLibraryDefinition.fileName
let requiredObject = require(path)
let requiredFunction = requiredObject[functionLibraryDefinition.functionName]
projectInstance.functionLibraries[functionLibraryDefinition.propertyName] = requiredFunction.call()
}
}
}
}
}
+32 -3
View File
@@ -64,12 +64,27 @@ let EVENT_SERVER = require('./eventServer.js')
let TASK_MANAGER_SERVER = require('./taskManagerServer.js')
let CCXT_SERVER = require('./ccxtServer.js')
let WEB3_SERVER = require('./web3Server.js')
let GITHUB_SERVER = require('./githubServer.js')
/* Network Interfaces */
let WEB_SOCKETS_INTERFACE = require('./webSocketsServer.js')
let HTTP_INTERFACE = require('./httpInterface.js')
try {
/*
Setting up the modules that will be available for the Servers Running inside this Client
*/
let MULTI_PROJECT = require('./MultiProject.js');
let MULTI_PROJECT_MODULE = MULTI_PROJECT.newMultiProject()
MULTI_PROJECT_MODULE.initialize()
/*
Setting up external dependencies.
*/
CL.nodeModules = {
fs: require('fs'),
nodeFetch: require('node-fetch')
}
console.log('CLIENT SERVERS:')
console.log('')
@@ -87,7 +102,7 @@ try {
PROJECT_FILE_SERVER.initialize()
PROJECT_FILE_SERVER.run()
console.log('Project File Server ......................................... Started')
PLUGIN_SERVER = PLUGIN_SERVER.newPluginServer()
PLUGIN_SERVER.initialize()
PLUGIN_SERVER.run()
@@ -112,12 +127,17 @@ try {
CCXT_SERVER.initialize()
CCXT_SERVER.run()
console.log('CCXT Server ................................................. Started')
WEB3_SERVER = WEB3_SERVER.newWeb3Server()
WEB3_SERVER.initialize()
WEB3_SERVER.run()
console.log('WEB3 Server ................................................. Started')
GITHUB_SERVER = GITHUB_SERVER.newGithubServer()
GITHUB_SERVER.initialize()
GITHUB_SERVER.run()
console.log('Github Server ............................................... Started')
console.log('')
console.log('CLIENT INTERFACES:')
console.log('')
@@ -127,7 +147,16 @@ try {
WEB_SOCKETS_INTERFACE.run()
console.log('Web Sockets Interface ....................................... Listening at port ' + global.env.WEB_SOCKETS_INTERFACE_PORT)
HTTP_INTERFACE = HTTP_INTERFACE.newHttpInterface(WEB_SERVER, DATA_FILE_SERVER, PROJECT_FILE_SERVER, UI_FILE_SERVER, PLUGIN_SERVER, CCXT_SERVER, WEB3_SERVER)
HTTP_INTERFACE = HTTP_INTERFACE.newHttpInterface(
WEB_SERVER,
DATA_FILE_SERVER,
PROJECT_FILE_SERVER,
UI_FILE_SERVER,
PLUGIN_SERVER,
CCXT_SERVER,
WEB3_SERVER,
GITHUB_SERVER
)
HTTP_INTERFACE.initialize()
HTTP_INTERFACE.run()
console.log('Http Interface .............................................. Listening at port ' + global.env.HTTP_INTERFACE_PORT)
+585
View File
@@ -0,0 +1,585 @@
exports.newGithubServer = function newGithubServer() {
let thisObject = {
getGithubStars: getGithubStars,
getGithubWatchers: getGithubWatchers,
getGithubForks: getGithubForks,
mergePullRequests: mergePullRequests,
initialize: initialize,
finalize: finalize,
run: run
}
const GITHUB_API_WAITING_TIME = 250
return thisObject
function finalize() {
}
function initialize() {
}
function run() {
}
async function getGithubStars(repository, username, token) {
return await getGithubUsernames('activity', 'listStargazersForRepo', repository, username, token)
}
async function getGithubWatchers(repository, username, token) {
return await getGithubUsernames('activity', 'listWatchersForRepo', repository, username, token)
}
async function getGithubForks(repository, username, token) {
return await getGithubUsernames('repos', 'listForks', repository, username, token)
}
async function mergePullRequests(commitMessage, username, token) {
return await mergeGithubPullRequests(commitMessage, username, token)
}
async function getGithubUsernames(endpoint, method, repository, username, token) {
try {
repository = unescape(repository)
username = unescape(username)
token = unescape(token)
let error
let githubListArray = []
return await getRepoInfo()
async function getRepoInfo() {
await doGithub()
if (error !== undefined) {
let docs = {
project: 'Governance',
category: 'Topic',
type: 'Gov Error - Get Repository Information',
anchor: undefined,
placeholder: {}
}
return respondWithDocsObject(docs, error)
}
return {
result: global.DEFAULT_OK_RESPONSE.result,
githubListArray: githubListArray
}
}
async function doGithub() {
const { Octokit } = require("@octokit/rest")
const octokit = new Octokit({
auth: token,
userAgent: 'Superalgos Beta 11'
})
await getList()
async function getList() {
const repo = repository
const owner = 'Superalgos'
const per_page = 100 // Max
let page = 0
let lastPage = false
while (lastPage === false) {
try {
page++
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
let listResponse = await octokit[endpoint][method]({
owner,
repo,
per_page,
page
});
if (listResponse.data.length < 100) {
lastPage = true
}
for (let i = 0; i < listResponse.data.length; i++) {
let listItem = listResponse.data[i]
let githubUsername
switch (endpoint) {
case 'activity': {
githubUsername = listItem.login
break
}
case 'repos': {
githubUsername = listItem.owner.login
break
}
}
//console.log(listItem)
githubListArray.push(githubUsername)
}
console.log('[INFO] Github Server -> getRepoInfo -> doGithub -> getList -> ' + method + ' Page = ' + page)
console.log('[INFO] Github Server -> getRepoInfo -> doGithub -> getList -> ' + method + ' Received = ' + listResponse.data.length)
} catch (err) {
console.log(err)
if (err.stack.indexOf('last page') >= 0) {
return
} else {
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->Method call produced an error.')
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->err.stack = ' + err.stack)
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->repository = ' + repository)
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->username = ' + username)
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->token ends with = ' + '...' + token.substring(token.length - 10))
error = err
return
}
}
}
}
}
} catch (err) {
console.log('[ERROR] Github Server -> getRepoInfo -> Method call produced an error.')
console.log('[ERROR] Github Server -> getRepoInfo -> err.stack = ' + err.stack)
console.log('[ERROR] Github Server -> getRepoInfo -> repository = ' + repository)
console.log('[ERROR] Github Server -> getRepoInfo -> username = ' + username)
console.log('[ERROR] Github Server -> getRepoInfo -> token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] Github Server -> getRepoInfo -> token ends with = ' + '...' + token.substring(token.length - 10))
let error = {
result: 'Fail Because',
message: err.message,
stack: err.stack
}
return error
}
}
async function mergeGithubPullRequests(commitMessage, username, token) {
try {
commitMessage = unescape(commitMessage)
username = unescape(username)
token = unescape(token)
const repository = 'Superalgos'
/* Unsavping # */
for (let i = 0; i < 10; i++) {
commitMessage = commitMessage.replace('_SLASH_', '/')
commitMessage = commitMessage.replace('_HASHTAG_', '#')
}
let error
let githubPrListArray = []
return await processOpenPullRequests()
async function processOpenPullRequests() {
await doGithub()
if (error !== undefined) {
let docs = {
project: 'Governance',
category: 'Topic',
type: 'Gov Error - Pull Requests Not Processed',
anchor: undefined,
placeholder: {}
}
return respondWithDocsObject(docs, error)
}
return {
result: global.DEFAULT_OK_RESPONSE.result
}
}
async function doGithub() {
try {
const repo = repository
const owner = 'Superalgos'
const { Octokit } = require("@octokit/rest")
const octokit = new Octokit({
auth: token,
userAgent: 'Superalgos Beta 11'
})
await getPrList()
await mergePrs()
async function getPrList() {
const per_page = 100 // Max
let page = 0
let lastPage = false
while (lastPage === false) {
try {
page++
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
let listResponse = await octokit.rest.pulls.list({
owner: owner,
repo: repo,
state: 'open',
head: 'develop',
base: 'develop',
sort: undefined,
direction: undefined,
per_page: per_page,
page: page
});
if (listResponse.data.length < 100) {
lastPage = true
}
console.log('[INFO] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList -> Receiving Page = ' + page)
for (let i = 0; i < listResponse.data.length; i++) {
let pullRequest = listResponse.data[i]
console.log('[INFO] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList -> Pull Request "' + pullRequest.title + '" found and added to the list to validate. ')
githubPrListArray.push(pullRequest)
}
console.log('[INFO] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList -> Received = ' + listResponse.data.length)
} catch (err) {
console.log(err)
if (err.stack.indexOf('last page') >= 0) {
return
} else {
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->Method call produced an error.')
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->err.stack = ' + err.stack)
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->repository = ' + repository)
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->username = ' + username)
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->token ends with = ' + '...' + token.substring(token.length - 10))
error = err
return
}
}
}
}
async function mergePrs() {
/*
In order to automatically merge a PRs we will run several validations first.
We want to automate specifically the merging of Profile File changes at the
Governance System done by the same Github user name that matches the profile
changed. We will also not do the merge if there are more than one file at the
PR.
We will go through the list of open PRs and run the validations at each one of them.
*/
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Ready to Validate ' + githubPrListArray.length + ' pull requests. ')
for (let i = 0; i < githubPrListArray.length; i++) {
let pullRequest = githubPrListArray[i]
/*
Lets get the files changed at this Pull Request.
*/
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
let listResponse = await octokit.rest.pulls.listFiles({
owner: owner,
repo: repo,
pull_number: pullRequest.number
});
let filesChanged = listResponse.data
let fileContentUrl // URL to the only file at the PR
let fileContent // File content of the only file at the PR
let userProfile // User Profile Object
let githubUsername // The Github user name of who is submitting the Pull Request
let mergeResponse // The response received from the call to Gihub to merge the Pull Request
if (await validatePrHasMoreThanOneFile() === false) { continue }
if (await validateFileNameEqualsGithubUsername() === false) { continue }
if (await validateFileChangedIsUserProfile() === false) { continue }
if (await validateMessageSignedIsGithubUsername() === false) { continue }
if (await validateUserProfileNodeNameEqualsGithubUsername() === false) { continue }
if (await validateUserProfileIdDoesNotBelongtoAnotherUserProfile() === false) { continue }
if (await mergePullRequest() === false) {
console.log('[WARN] Github Server -> mergeGithubPullRequests -> Merge Failed -> Pull Request "' + pullRequest.title + '" not merged because Github could not merge it. -> mergeResponse.message = ' + mergeResponse.data.message)
} else {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Merge Succed -> Pull Request "' + pullRequest.title + '" successfully merged. -> mergeResponse.message = ' + mergeResponse.data.message)
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request was automatically merged by the Superalgos Governance System because it was detected that the Github User " ' + githubUsername + '" who submitted it, modified its own User Profile Plugin File and nothning else but that file. All validations were successfull.'
});
}
async function validatePrHasMoreThanOneFile() {
/*
Validation #1: If the PR has more than one file, then we will not automatically
merge it.
*/
if (filesChanged.length !== 1) {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #1 Failed -> Pull Request "' + pullRequest.title + '" not merged because it contains more than 1 file. -> fileCount = ' + filesChanged.length)
/*
We will close PRs that contains any User Profile file together with other files in the same Pull Request.
This will avoid manual merges to include User Profile files.
*/
for (let j = 0; j < filesChanged.length; j++) {
let pullRequestFile = filesChanged[j]
let fileContentUrl = pullRequestFile.raw_url
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') >= 0) {
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that a User Profile file... \n\n' + fileContentUrl + '\n\n...was submitted together with ' + (filesChanged.length - 1) + ' other file/s. User Profiles files as per the Governance System rules, must be the only file present at a Pull Request in order to pass all the validations and be automatically merged.'
});
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
break
}
}
return false
}
}
async function validateFileNameEqualsGithubUsername() {
/*
Validation #2: File Name must be the same to the Github Username of the PR owner.
*/
let pullRequestFile = filesChanged[0]
fileContentUrl = pullRequestFile.raw_url
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') < 0) {
/*
If it is not a user profile then there is no need to auto merge.
*/
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified at the Pull Request is not a User Profile file. -> fileContentUrl = ' + fileContentUrl)
return false
}
let splittedURL = fileContentUrl.split('/')
let fileName = splittedURL[splittedURL.length - 1]
let splittedFileName = fileName.split('.')
fileName = splittedFileName[0]
githubUsername = pullRequest.user.login
if (githubUsername !== fileName) {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the File Name. -> Github Username = ' + githubUsername + '-> fileName = ' + fileName)
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the name of the User Profile Plugin File.\n\n File Name = "' + fileName + '"'
});
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
return false
}
}
async function validateFileChangedIsUserProfile() {
/*
Validation #3: The file changed at the PR is a User Profile.
*/
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
fileContent = await CL.projects.foundations.utilities.webAccess.fetchAPIDataFile(fileContentUrl)
userProfile = JSON.parse(fileContent)
if (userProfile.type !== 'User Profile') {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #3 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified is not a User Profile. -> Type = ' + userProfile.type)
return false
}
}
async function validateMessageSignedIsGithubUsername() {
/*
Validation #4: The message signed at the config is not the Github Username.
*/
let config = JSON.parse(userProfile.config)
let messageSigned = config.signature.message
if (messageSigned !== githubUsername) {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #4 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the Message Signed at the User Profile. -> Github Username = ' + githubUsername + '-> messageSigned = ' + messageSigned)
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the Message Signed at the User Profile.\n\n Message Signed = "' + messageSigned + '"'
});
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
return false
}
}
async function validateUserProfileNodeNameEqualsGithubUsername() {
/*
Validation #5: The name of the User Profile node is not the Github Username.
*/
if (userProfile.name !== githubUsername) {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #5 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the User Profile node\'s name. -> Github Username = ' + githubUsername + '-> userProfile.name = ' + userProfile.name)
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the User Profile node\'s name.\n\n User Profile Name = "' + userProfile.name + '"'
});
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
return false
}
}
async function validateUserProfileIdDoesNotBelongtoAnotherUserProfile() {
/*
Validation #6: The id of the User Profile can not be the id of an already existing User Profile
unless the existing one belongs to the same Github username.
*/
let userProfileIdMap = new Map()
let pluginFileNames = await CL.projects.foundations.utilities.plugins.getPluginFileNames(
'Governance',
'User-Profiles'
)
for (let i = 0; i < pluginFileNames.length; i++) {
let pluginFileName = pluginFileNames[i]
let pluginFileContent = await CL.projects.foundations.utilities.plugins.getPluginFileContent(
'Governance',
'User-Profiles',
pluginFileName
)
let otherUserProfile = JSON.parse(pluginFileContent)
userProfileIdMap.set(otherUserProfile.id, otherUserProfile.name)
}
let testUserProfile = userProfileIdMap.get(userProfile.id)
if (testUserProfile === undefined) { return true }
if (testUserProfile !== userProfile.name) {
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #6 Failed -> Pull Request "' + pullRequest.title + '" not merged because the User Profile Id already exists and belongs to another User Profile on record. -> Profile Id = ' + userProfile.id + '-> User Profile with the same Id = ' + testUserProfile)
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because the User Profile Id already exists and belongs to another User Profile on record. \n\nUser Profile Id = "' + userProfile.id + '" \n\n User Profile with the same Id = "' + testUserProfile + '"'
});
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
return false
}
}
async function mergePullRequest() {
/*
All validations passed, we will proceed an merge this Pull Request.
*/
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
mergeResponse = await octokit.rest.pulls.merge({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
commit_title: 'Changes in User Profile done by Profile Owner ' + githubUsername + ' automatically merged by Superalgos.'
});
return mergeResponse.data.merged
}
}
}
} catch (err) {
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> err.stack = ' + err.stack)
}
}
} catch (err) {
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> Method call produced an error.')
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> err.stack = ' + err.stack)
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> repository = ' + repository)
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> username = ' + username)
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> token ends with = ' + '...' + token.substring(token.length - 10))
let error = {
result: 'Fail Because',
message: err.message,
stack: err.stack
}
return error
}
}
function respondWithDocsObject(docs, error) {
if (error.message !== undefined) {
docs.placeholder.errorMessage = {
style: 'Error',
text: error.message
}
}
if (error.stack !== undefined) {
docs.placeholder.errorStack = {
style: 'Javascript',
text: error.stack
}
}
if (error.code !== undefined) {
docs.placeholder.errorCode = {
style: 'Json',
text: error.code
}
}
docs.placeholder.errorDetails = {
style: 'Json',
text: JSON.stringify(error, undefined, 4)
}
let customResponse = {
result: global.CUSTOM_FAIL_RESPONSE.result,
docs: docs
}
return customResponse
}
}
+138 -497
View File
@@ -1,4 +1,13 @@
exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVER, PROJECT_FILE_SERVER, UI_FILE_SERVER, PLUGIN_SERVER, CCXT_SERVER, WEB3_SERVER) {
exports.newHttpInterface = function newHttpInterface(
WEB_SERVER,
DATA_FILE_SERVER,
PROJECT_FILE_SERVER,
UI_FILE_SERVER,
PLUGIN_SERVER,
CCXT_SERVER,
WEB3_SERVER,
GITHUB_SERVER
) {
/*
IMPORTANT: If you are reviewing the code of the project please note
@@ -151,6 +160,15 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
case 'mnemonicToPrivateKey': {
let serverResponse = await WEB3_SERVER.mnemonicToPrivateKey(
params.mnemonic
)
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
default: {
respondWithContent(JSON.stringify({ error: 'Method ' + params.method + ' is invalid.' }), httpResponse)
}
@@ -366,6 +384,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
}
break
}
case 'Save-Concept-Schema': {
getBody(processRequest)
@@ -396,6 +415,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
}
break
}
case 'Save-Topic-Schema': {
getBody(processRequest)
@@ -426,6 +446,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
}
break
}
case 'Save-Tutorial-Schema': {
getBody(processRequest)
@@ -456,6 +477,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
}
break
}
case 'Save-Review-Schema': {
getBody(processRequest)
@@ -486,6 +508,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
}
break
}
case 'Save-Book-Schema': {
getBody(processRequest)
@@ -1019,138 +1042,80 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
}
break
case 'Gov': {
switch (requestParameters[2]) { // switch by command
case 'getGithubStars': {
getGithubUsernames('activity', 'listStargazersForRepo')
break
}
case 'getGithubWatchers': {
getGithubUsernames('activity', 'listWatchersForRepo')
break
}
case 'getGithubForks': {
getGithubUsernames('repos', 'listForks')
break
}
case 'PRs': {
mergeGithubPullRequests()
break
}
case 'Pay': {
payToContributors()
break
}
}
case 'GOV': {
/*
This is the Governance endpoint at the Http Interface. All methods
related to the Governance System are implemented here and routed
to the backend Servers that can process them.
*/
getBody(processRequest)
function getGithubUsernames(endpoint, method) {
async function processRequest(body) {
try {
const GITHUB_API_WAITING_TIME = 250
const repository = unescape(requestParameters[3])
const username = unescape(requestParameters[4])
const token = unescape(requestParameters[5])
let error
let githubListArray = []
let params = JSON.parse(body)
getRepoInfo()
switch (params.method) {
case 'getGithubStars': {
async function getRepoInfo() {
await doGithub()
if (error !== undefined) {
let serverResponse = await GITHUB_SERVER.getGithubStars(
params.repository,
params.username,
params.token
)
let docs = {
project: 'Governance',
category: 'Topic',
type: 'Gov Error - Get Repository Information',
anchor: undefined,
placeholder: {}
}
respondWithDocsObject(docs, error)
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
case 'getGithubWatchers': {
respondWithContent(JSON.stringify(githubListArray), httpResponse)
}
let serverResponse = await GITHUB_SERVER.getGithubWatchers(
params.repository,
params.username,
params.token
)
async function doGithub() {
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
case 'getGithubForks': {
const { Octokit } = require("@octokit/rest")
let serverResponse = await GITHUB_SERVER.getGithubForks(
params.repository,
params.username,
params.token
)
const octokit = new Octokit({
auth: token,
userAgent: 'Superalgos Beta 11'
})
await getList()
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
case 'mergePullRequests': {
async function getList() {
const repo = repository
const owner = 'Superalgos'
const per_page = 100 // Max
let page = 0
let lastPage = false
let serverResponse = await GITHUB_SERVER.mergePullRequests(
params.commitMessage,
params.username,
params.token
)
while (lastPage === false) {
try {
page++
await sleep(GITHUB_API_WAITING_TIME)
let listResponse = await octokit[endpoint][method]({
owner,
repo,
per_page,
page
});
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
case 'payContributors': {
if (listResponse.data.length < 100) {
lastPage = true
}
let serverResponse = await WEB3_SERVER.payContributors(
params.signature
)
for (let i = 0; i < listResponse.data.length; i++) {
let listItem = listResponse.data[i]
let githubUsername
switch (endpoint) {
case 'activity': {
githubUsername = listItem.login
break
}
case 'repos': {
githubUsername = listItem.owner.login
break
}
}
//console.log(listItem)
githubListArray.push(githubUsername)
}
console.log('[INFO] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList -> ' + method + ' Page = ' + page)
console.log('[INFO] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList -> ' + method + ' Received = ' + listResponse.data.length)
} catch (err) {
console.log(err)
if (err.stack.indexOf('last page') >= 0) {
return
} else {
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->Method call produced an error.')
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->repository = ' + repository)
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->username = ' + username)
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->token ends with = ' + '...' + token.substring(token.length - 10))
error = err
}
}
}
respondWithContent(JSON.stringify(serverResponse), httpResponse)
return
}
default: {
respondWithContent(JSON.stringify({ error: 'Method ' + params.method + ' is invalid.' }), httpResponse)
}
}
} catch (err) {
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> Method call produced an error.')
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> repository = ' + repository)
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> username = ' + username)
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> token ends with = ' + '...' + token.substring(token.length - 10))
console.log('[ERROR] httpInterface -> GOV -> Method call produced an error.')
console.log('[ERROR] httpInterface -> GOV -> err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> GOV -> Params Received = ' + body)
let error = {
result: 'Fail Because',
@@ -1160,332 +1125,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
respondWithContent(JSON.stringify(error), httpResponse)
}
}
function respondWithDocsObject(docs, error) {
if (error.message !== undefined) {
docs.placeholder.errorMessage = {
style: 'Error',
text: error.message
}
}
if (error.stack !== undefined) {
docs.placeholder.errorStack = {
style: 'Javascript',
text: error.stack
}
}
if (error.code !== undefined) {
docs.placeholder.errorCode = {
style: 'Json',
text: error.code
}
}
docs.placeholder.errorDetails = {
style: 'Json',
text: JSON.stringify(error, undefined, 4)
}
let customResponse = {
result: global.CUSTOM_FAIL_RESPONSE.result,
docs: docs
}
respondWithContent(JSON.stringify(customResponse), httpResponse)
}
function mergeGithubPullRequests() {
try {
let commitMessage = unescape(requestParameters[3])
/* Unsavping # */
for (let i = 0; i < 10; i++) {
commitMessage = commitMessage.replace('_SLASH_', '/')
commitMessage = commitMessage.replace('_HASHTAG_', '#')
}
const GITHUB_API_WAITING_TIME = 250
const repository = 'Superalgos'
const username = unescape(requestParameters[4])
const token = unescape(requestParameters[5])
let error
let githubPrListArray = []
processOpenPullRequests()
async function processOpenPullRequests() {
await doGithub()
if (error !== undefined) {
let docs = {
project: 'Governance',
category: 'Topic',
type: 'Gov Error - Merge Pull Requests',
anchor: undefined,
placeholder: {}
}
respondWithDocsObject(docs, error)
return
}
respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), httpResponse)
}
async function doGithub() {
try {
const repo = repository
const owner = 'Superalgos'
const { Octokit } = require("@octokit/rest")
const octokit = new Octokit({
auth: token,
userAgent: 'Superalgos Beta 11'
})
await getPrList()
await mergePrs()
async function getPrList() {
const per_page = 100 // Max
let page = 0
let lastPage = false
while (lastPage === false) {
try {
page++
await sleep(GITHUB_API_WAITING_TIME)
let listResponse = await octokit.rest.pulls.list({
owner: owner,
repo: repo,
state: 'open',
head: 'develop',
base: 'develop',
sort: undefined,
direction: undefined,
per_page: per_page,
page: page
});
if (listResponse.data.length < 100) {
lastPage = true
}
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList -> Receiving Page = ' + page)
for (let i = 0; i < listResponse.data.length; i++) {
let pullRequest = listResponse.data[i]
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList -> Pull Request "' + pullRequest.title + '" found and added to the list to validate. ')
githubPrListArray.push(pullRequest)
}
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList -> Received = ' + listResponse.data.length)
} catch (err) {
console.log(err)
if (err.stack.indexOf('last page') >= 0) {
return
} else {
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->Method call produced an error.')
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->repository = ' + repository)
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->username = ' + username)
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->token ends with = ' + '...' + token.substring(token.length - 10))
error = err
}
}
}
}
async function mergePrs() {
/*
In order to automatically merge a PRs we will run several validations first.
We want to automate specifically the merging of Profile File changes at the
Governance System done by the same Github user name that matches the profile
changed. We will also not do the merge if there are more than one file at the
PR.
We will go through the list of open PRs and run the validations at each one of them.
*/
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Ready to Validate ' + githubPrListArray.length + ' pull requests. ')
for (let i = 0; i < githubPrListArray.length; i++) {
let pullRequest = githubPrListArray[i]
/*
Lets get the files changed at this Pull Request.
*/
await sleep(GITHUB_API_WAITING_TIME)
let listResponse = await octokit.rest.pulls.listFiles({
owner: owner,
repo: repo,
pull_number: pullRequest.number
});
/*
Validation #1: If the PR has more than one file, then we will not automatically
merge it.
*/
if (listResponse.data.length !== 1) {
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #1 Failed -> Pull Request "' + pullRequest.title + '" not merged because it contains more than 1 file. -> fileCount = ' + listResponse.data.length)
/*
We will close PRs that contains any User Profile file together with other files in the same Pull Request.
This will avoid manual merges to include User Profile files.
*/
for (j = 0; j < listResponse.data.length; j++) {
let pullRequestFile = listResponse.data[j]
let fileContentUrl = pullRequestFile.raw_url
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') >= 0) {
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that a User Profile file... \n\n' + fileContentUrl + '\n\n...was submitted together with ' + (listResponse.data.length - 1) + ' other file/s. User Profiles files as per the Governance System rules, must be the only file present at a Pull Request in order to pass all the validations and be automatically merged.'
});
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
break
}
}
continue
}
let pullRequestFile = listResponse.data[0]
/*
Validation #2: File Name must be the same to the Github Username of the PR owner.
*/
let fileContentUrl = pullRequestFile.raw_url
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') < 0) {
/*
If it is not a user profile then there is no need to auto merge.
*/
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified at the Pull Request is not a User Profile file. -> fileContentUrl = ' + fileContentUrl)
continue
}
let splittedURL = fileContentUrl.split('/')
let fileName = splittedURL[splittedURL.length - 1]
let splittedFileName = fileName.split('.')
fileName = splittedFileName[0]
let githubUsername = pullRequest.user.login
if (githubUsername !== fileName) {
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the File Name. -> Github Username = ' + githubUsername + '-> fileName = ' + fileName)
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the name of the User Profile Plugin File.\n\n File Name = "' + fileName + '"'
});
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
continue
}
await sleep(GITHUB_API_WAITING_TIME)
let fileContent = await fetchAPIDataFile(fileContentUrl)
let userProfile = JSON.parse(fileContent)
/*
Validation #3: The file changed at the PR is a User Profile.
*/
if (userProfile.type !== 'User Profile') {
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #3 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified is not a User Profile. -> Type = ' + userProfile.type)
continue
}
/*
Validation #4: The message signed at the config is not the Github Username.
*/
let config = JSON.parse(userProfile.config)
let messageSigned = config.signature.message
if (messageSigned !== githubUsername) {
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #4 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the Message Signed at the User Profile. -> Github Username = ' + githubUsername + '-> messageSigned = ' + messageSigned)
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the Message Signed at the User Profile.\n\n Message Signed = "' + messageSigned + '"'
});
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
state: 'closed'
});
continue
}
/*
All validations passed, we will proceed an merge this Pull Request.
*/
await sleep(GITHUB_API_WAITING_TIME)
let mergeResponse = await octokit.rest.pulls.merge({
owner: owner,
repo: repo,
pull_number: pullRequest.number,
commit_title: 'Changes in User Profile done by Profile Owner ' + githubUsername + ' automatically merged by Superalgos.'
});
if (mergeResponse.data.merged !== true) {
console.log('[WARN] httpInterface -> Gov -> mergeGithubPullRequests -> Merge Failed -> Pull Request "' + pullRequest.title + '" not merged because Github could not merge it. -> mergeResponse.message = ' + mergeResponse.data.message)
continue
} else {
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Merge Succed -> Pull Request "' + pullRequest.title + '" successfully merged. -> mergeResponse.message = ' + mergeResponse.data.message)
await sleep(GITHUB_API_WAITING_TIME)
await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: pullRequest.number,
body: 'This Pull Request was automatically merged by the Superalgos Governance System because it was detected that the Github User " ' + githubUsername + '" who submitted it, modified its own User Profile Plugin File and nothning else but that file. All validations were successfull.'
});
continue
}
}
}
} catch (err) {
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> err.stack = ' + err.stack)
}
}
} catch (err) {
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> Method call produced an error.')
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> repository = ' + repository)
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> username = ' + username)
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> token starts with = ' + token.substring(0, 10) + '...')
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> token ends with = ' + '...' + token.substring(token.length - 10))
let error = {
result: 'Fail Because',
message: err.message,
stack: err.stack
}
respondWithContent(JSON.stringify(error), httpResponse)
}
}
function payToContributors() {
}
}
break
}
case 'LegacyPlotter.js':
{
@@ -1701,30 +1342,70 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
case 'PluginFileNames':
{
let project = unescape(requestParameters[2])
let pluginType = unescape(requestParameters[3])
processRequest()
const fs = require('fs')
let folder = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + pluginType
async function processRequest(body) {
try {
let project = unescape(requestParameters[2])
let folder = unescape(requestParameters[3])
fs.readdir(folder, (err, files) => {
if (files === undefined) {
files = []
let response = await CL.projects.foundations.utilities.plugins.getPluginFileNames(
project,
folder
)
respondWithContent(JSON.stringify(response), httpResponse)
} catch (err) {
console.log('[ERROR] httpInterface -> PluginFileNames -> Method call produced an error.')
console.log('[ERROR] httpInterface -> PluginFileNames -> err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> PluginFileNames -> Params Received = ' + body)
let error = {
result: 'Fail Because',
message: err.message,
stack: err.stack
}
respondWithContent(JSON.stringify(error), httpResponse)
}
respondWithContent(JSON.stringify(files), httpResponse)
})
}
break
}
break
case 'LoadPlugin':
{
let project = unescape(requestParameters[2])
let pluginType = unescape(requestParameters[3])
let fileName = unescape(requestParameters[4])
let filePath = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + pluginType + '/' + fileName
respondWithFile(filePath, httpResponse)
processRequest()
async function processRequest(body) {
try {
let project = unescape(requestParameters[2])
let folder = unescape(requestParameters[3])
let fileName = unescape(requestParameters[4])
let response = await CL.projects.foundations.utilities.plugins.getPluginFileContent(
project,
folder,
fileName
)
respondWithContent(response, httpResponse)
} catch (err) {
console.log('[ERROR] httpInterface -> LoadPlugin -> Method call produced an error.')
console.log('[ERROR] httpInterface -> LoadPlugin -> err.stack = ' + err.stack)
console.log('[ERROR] httpInterface -> LoadPlugin -> Params Received = ' + body)
let error = {
result: 'Fail Because',
message: err.message,
stack: err.stack
}
respondWithContent(JSON.stringify(error), httpResponse)
}
}
break
}
break
case 'SavePlugin':
getBody(processRequest)
@@ -1831,7 +1512,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
function onDirRead(err, fileList) {
if (err) {
// This happens the first time you run the software.
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
respondWithContent(JSON.stringify(allWorkspaces), httpResponse)
return
} else {
let updatedFileList = []
@@ -2431,44 +2112,4 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
return files.reduce((a, f) => a.concat(f), []);
}
}
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function fetchAPIDataFile(url) {
let promise = new Promise((resolve, reject) => {
const fetch = require('node-fetch')
/*
This is how we call the API.
*/
fetch(url)
.then((response) => {
if (response.status !== 200) {
console.log('[ERROR] fetchAPIData -> then -> url =' + url)
reject()
return
}
getResponseBody()
function getResponseBody() {
response.text().then(body => {
resolve(body)
})
}
})
.catch(err => {
console.log('[ERROR] fetchAPIData -> url =' + url)
reject()
})
}
)
return promise
}
}
+274 -4190
View File
File diff suppressed because it is too large. Load diff
+3 -2
View File
@@ -10,12 +10,13 @@
"@octokit/rest": "^18.9.0",
"ccxt": "^1.51.98",
"child_process": "^1.0.2",
"ethers": "^5.4.4",
"lookpath": "^1.2.2",
"node-fetch": "2.6.1",
"open": "^6.4.0",
"rimraf": "^3.0.2",
"simple-git": "^2.42.0",
"web3": "^1.5.0",
"ws": "^7.4.6",
"node-fetch": "2.6.1"
"ws": "^7.4.6"
}
}
+26
View File
@@ -8,6 +8,7 @@ exports.newWeb3Server = function newWeb3Server() {
getWalletBalances: getWalletBalances,
signData: signData,
recoverAddress: recoverAddress,
mnemonicToPrivateKey: mnemonicToPrivateKey,
initialize: initialize,
finalize: finalize,
run: run
@@ -236,4 +237,29 @@ exports.newWeb3Server = function newWeb3Server() {
return { error: 'Could not recover address. ' + err.stack }
}
}
async function mnemonicToPrivateKey(mnemonic) {
try {
const ethers = require('ethers')
let wallet = ethers.Wallet.fromMnemonic(mnemonic)
if (wallet.privateKey !== undefined) {
return {
address: wallet.address,
privateKey: wallet.privateKey,
result: 'Ok'
}
} else {
return {
address: undefined,
privateKey: undefined,
result: 'Fail'
}
}
} catch (err) {
return { error: 'Could not convert to Private Key. ' + err.stack }
}
}
}
+12 -8
View File
@@ -16,7 +16,7 @@ Node JS is an open-source server environment required to run Superalgos.
**A.** Go to the Node JS [download page](https://nodejs.org/en/download/).
**B.** Download your system’s installer. Select *LTS Recommended for Most Users* and click the big Windows or macOS Installer button. If you are on Linux, the installer is listed further down the page.
**B.** Download your system's installer. Select *LTS Recommended for Most Users* and click the big Windows or macOS Installer button. If you are on Linux, the installer is listed further down the page.
**C.** Run the installer with the default configuration — just click Next until Node.JS is fully installed. That's it! You can continue with step 2 (Git Installation).
@@ -94,13 +94,13 @@ Before you begin, it is recommended that you set up Chrome/Safari as your defaul
**A.** Scroll the page all the way to the top. Find and click the **Fork** button to create your fork/copy of this repository. To fork Superalgos you need a Github account. If you don't have one, go ahead and create it.
**NOTE:** A Fork is required for your contributions to the project. The reason why Superalgos is free and open-source is that the project has set up a <a href="https://superalgos.org/community-business.shtml" target="_blank">Collective Business</a> in which all users may participate. The way to participate is to <a href="https://superalgos.org/community-contribute.shtml" target="_blank">contribute</a> to make Superalgos better. The project's <a href="https://superalgos.org/token-overview.shtml" target="_blank">token</a> is distributed among contributors.
**NOTE:** A Fork is required for your contributions to the project. The reason why Superalgos is free and open-source is that the project has set up a <a href="https://superalgos.org/project-one-pager.shtml" target="_blank">Collective Business</a> in which all users may participate. The way to participate is to <a href="https://superalgos.org/community-contribute.shtml" target="_blank">contribute</a> to make Superalgos better. The project's <a href="https://superalgos.org/token-overview.shtml" target="_blank">token</a> is distributed among contributors.
## 2. Clone Your Fork
**A.** Once the fork is created, you will land on the page of your fork. Copy the URL from your browser's address bar.
**B.** In your computer/laptop/server, open a command prompt or terminal. Make sure you are in a directory where you have write permissions (on most systems the terminal will open in your user’s home directory, so you’re good). Clone the git repository using the command:
**B.** In your computer/laptop/server, open a command prompt or terminal. Make sure you are in a directory where you have write permissions (on most systems the terminal will open in your user's home directory, so you're good). Clone the git repository using the command:
```
git clone <URL of your Superalgos fork>
@@ -116,9 +116,13 @@ This creates the `Superalgos` folder in the current directory, which contains th
## 3. Install Node Dependencies
**A.** After the Superalgos directory has been installed, the final step of installation is to set up the necessary node dependencies.
After the Superalgos directory has been installed, the final step of installation is to set up the necessary node dependencies. In the same command prompt or terminal you just used, type the following:
**B.** In the same command prompt or terminal you just used, type the following command:
```
cd Superalgos
```
That should take you inside the Superalgos folder created by the `git clone` command earlier. Now, run the following command:
```
node setup
@@ -233,7 +237,7 @@ We are testing the UI on Google Chrome and Safari on macOS only. It may work on
# Running Superalgos on a Headless Linux Server as a Daemon
If you’re running Superalgos on a headless linux server like a Raspberry Pi, you might want to run it as a daemon so it isn’t attached to your current login session. The easiest, most standard way to go about this is probably using `systemd`. Most linux distributions use it as default init system/service manager.
If you're running Superalgos on a headless linux server like a Raspberry Pi, you might want to run it as a daemon so it isn't attached to your current login session. The easiest, most standard way to go about this is probably using `systemd`. Most linux distributions use it as default init system/service manager.
## Using `systemd`
@@ -252,7 +256,7 @@ ExecStart=/usr/bin/node run minMemo noBrowser
WantedBy=multi-user.target
```
There is no need to run Superalgos as root so we’re running it as a user. The `minMemo` option assumes you’re running on a small machine like a Raspberry Pi, while `noBrowser` makes sense for running daemonized.
There is no need to run Superalgos as root so we're running it as a user. The `minMemo` option assumes you're running on a small machine like a Raspberry Pi, while `noBrowser` makes sense for running daemonized.
Now, as root (or using `sudo`), put the file `superalgos.service` you just created in `/etc/systemd/system/` and issue the command
```
@@ -290,7 +294,7 @@ Once the app finishes loading, an interactive tutorial takes you by the hand and
![welcome-tutorial-00](https://user-images.githubusercontent.com/13994516/107038771-4a6bf100-67bd-11eb-92e0-353525a972a9.gif)
**NOTE:** The tutorial uses Binance or Binance US as the exchange of choice. If you don’t have an account with Binance or Binance US, you will still be able to follow 100% of the tutorial. When you get to the live trading section, keep going even if you don't intend to run the session. You may learn how to work with other exchanges later on.
**NOTE:** The tutorial uses Binance or Binance US as the exchange of choice. If you don't have an account with Binance or Binance US, you will still be able to follow 100% of the tutorial. When you get to the live trading section, keep going even if you don't intend to run the session. You may learn how to work with other exchanges later on.
# Docker Deployments
@@ -0,0 +1,14 @@
exports.newFoundationsUtilitiesAsyncFunctions = function () {
let thisObject = {
sleep: sleep
}
return thisObject
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
}
@@ -0,0 +1,49 @@
exports.newFoundationsUtilitiesPlugins = function () {
let thisObject = {
getPluginFileNames: getPluginFileNames,
getPluginFileContent: getPluginFileContent
}
return thisObject
async function getPluginFileNames(project, folder) {
let promise = new Promise((resolve, reject) => {
let path = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + folder
CL.nodeModules.fs.readdir(path, (err, files) => {
if (err) {
reject()
return
}
if (files === undefined) {
files = []
}
resolve(files)
})
}
)
return promise
}
async function getPluginFileContent(project, folder, fileName) {
let promise = new Promise((resolve, reject) => {
let path = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + folder + '/' + fileName
CL.nodeModules.fs.readFile(path, onFileRead)
function onFileRead(err, file) {
if (err) {
reject()
return
}
resolve(file.toString())
}
}
)
return promise
}
}
@@ -0,0 +1,40 @@
exports.newFoundationsUtilitiesWebAccess = function () {
let thisObject = {
fetchAPIDataFile: fetchAPIDataFile
}
return thisObject
async function fetchAPIDataFile(url) {
let promise = new Promise((resolve, reject) => {
const fetch = CL.nodeModules.nodeFetch
/*
This is how we call the API.
*/
fetch(url)
.then((response) => {
if (response.status !== 200) {
console.log('[ERROR] fetchAPIData -> then -> url =' + url)
reject()
return
}
getResponseBody()
function getResponseBody() {
response.text().then(body => {
resolve(body)
})
}
})
.catch(err => {
console.log('[ERROR] fetchAPIData -> url =' + url)
reject()
})
}
)
return promise
}
}
File diff suppressed because it is too large. Load diff
@@ -60159,7 +60159,6 @@
"arrangementStyle": 0
},
"uiObject": {
"isPlaying": false,
"isRunning": false
},
"tutorial": {
@@ -62416,7 +62415,7 @@
"referenceParent": {
"type": "Workspace",
"name": "Getting Started Tutorials",
"id": "e927ea33-b88c-4524-97bb-07bbfea501f2"
"id": "90718523-1d6d-49a5-893c-803a492fdb43"
},
"referenceParentCombinedNodePath": [
[
@@ -63381,7 +63380,6 @@
"arrangementStyle": 0
},
"uiObject": {
"isPlaying": false,
"isRunning": false
},
"tutorial": {
@@ -69872,6 +69870,7 @@
"arrangementStyle": 0
},
"uiObject": {
"isPlaying": true,
"isRunning": false
},
"tutorial": {
@@ -9,8 +9,8 @@
},
{
"action": "Add UI Object",
"label": "Add Dependency Product Folder",
"relatedUiObject": "Dependency Product Folder",
"label": "Add Data Dependency Folder",
"relatedUiObject": "Data Dependency Folder",
"actionFunction": "payload.executeAction"
},
{
@@ -10,6 +10,7 @@
{
"action": "Add UI Object",
"label": "Add Tutorial",
"iconProject": "Education",
"relatedUiObject": "Tutorial",
"actionFunction": "payload.executeAction"
},
@@ -4,6 +4,7 @@
{
"action": "Add Missing Plugin Tutorials",
"label": "Add Missing Tutorials",
"iconProject": "Education",
"askConfirmation": true,
"confirmationLabel": "Confirm to Proceed",
"workDoneLabel": "Done",
@@ -1,7 +1,14 @@
{
"type": "Data Mine Tasks",
"definition": {
"text": "The data mine tasks node is an organizational device that groups tasks corresponding to the referenced data mine."
"text": "The data mine tasks node is an organizational device that groups tasks corresponding to the referenced data mine.",
"translations": [
{
"language": "ES",
"text": "El nodo data mine tasks es un dispositivo organizativo que agrupa las tareas correspondientes a la mina de datos referenciada.",
"updated": 1629581022406
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Manage Stage",
"definition": {
"text": "The manage stage deals with the setting and management of stop loss and take profit targets, both to protect your capital and to increase the efficiency of your trading system."
"text": "The manage stage deals with the setting and management of stop loss and take profit targets, both to protect your capital and to increase the efficiency of your trading system.",
"translations": [
{
"language": "ES",
"text": "El manage stage se ocupa del establecimiento y la gestión de objetivos de stop loss y take profit, tanto para proteger su capital como para aumentar la eficiencia de su sistema de trading.",
"updated": 1629580869439
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Market Sell Order",
"definition": {
"text": "A market sell order is an instruction sent to the exchange to sell the base asset, for immediate execution at current market prices."
"text": "A market sell order is an instruction sent to the exchange to sell the base asset, for immediate execution at current market prices.",
"translations": [
{
"language": "ES",
"text": "Un market sell orderes una instrucción enviada a la bolsa para vender el activo base, para su ejecución inmediata a los precios actuales del mercado.",
"updated": 1629580936448
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Position",
"definition": {
"text": "Position is the section of the data structure that keeps track of information within the scope of each position, and during the time a position is open."
"text": "Position is the section of the data structure that keeps track of information within the scope of each position, and during the time a position is open.",
"translations": [
{
"language": "ES",
"text": "Position es la sección de la estructura de datos que realiza un seguimiento de la información dentro del alcance de cada puesto, y durante el tiempo que un puesto está abierto.",
"updated": 1629580398836
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Slippage",
"definition": {
"text": "The slippage is an assumption on the difference between the simulated rate and the actual fill rate of a market order, most relevant in the context of backtesting and paper-trading sessions. The parameter is a tool to make simulations more realistic."
"text": "The slippage is an assumption on the difference between the simulated rate and the actual fill rate of a market order, most relevant in the context of backtesting and paper-trading sessions. The parameter is a tool to make simulations more realistic.",
"translations": [
{
"language": "ES",
"text": "El slippage es una suposición sobre la diferencia entre la tasa simulada y la tasa de ejecución real de una orden de mercado, más relevante en el contexto de las sesiones de backtesting y de paper-trading. El parámetro es una herramienta para hacer que las simulaciones sean más realistas.",
"updated": 1629581196113
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Stop Loss",
"definition": {
"text": "Stop loss is the current stop loss target, as defined in the manage stage of the corresponding strategy."
"text": "Stop loss is the current stop loss target, as defined in the manage stage of the corresponding strategy.",
"translations": [
{
"language": "ES",
"text": "Stop loss es el objetivo actual de stop loss, según se define en la etapa de gestión de la estrategia correspondiente.",
"updated": 1629580794189
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Strategies",
"definition": {
"text": "Strategies counts the number of times strategies have been triggered-on, in the context of the parent node."
"text": "Strategies counts the number of times strategies have been triggered-on, in the context of the parent node.",
"translations": [
{
"language": "ES",
"text": "Strategies cuenta el número de veces que se han activado las estrategias, en el contexto del nodo padre.",
"updated": 1629581287671
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Strategy",
"definition": {
"text": "The strategy section of the trading engine keeps track of information relating to the trading strategies that are triggered-on, during the time they remain open."
"text": "The strategy section of the trading engine keeps track of information relating to the trading strategies that are triggered-on, during the time they remain open.",
"translations": [
{
"language": "ES",
"text": "El strategy sección del motor de trading realiza un seguimiento de la información relacionada con las estrategias de trading que se activan, durante el tiempo que permanecen abiertas.",
"updated": 1629580247307
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Take Profit",
"definition": {
"text": "Take profit is the current take profit target, as defined in the manage stage of the corresponding strategy."
"text": "Take profit is the current take profit target, as defined in the manage stage of the corresponding strategy.",
"translations": [
{
"language": "ES",
"text": "Take profit es el objetivo actual de obtención de beneficios, según se define en la etapa de gestión de la estrategia correspondiente.",
"updated": 1629579903804
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Target Rate",
"definition": {
"text": "The target rate is a reference rate that may affect simulations and that, in combination with the placement of managed stop loss and managed take profit targets, is used to determine whether the targets have been hit."
"text": "The target rate is a reference rate that may affect simulations and that, in combination with the placement of managed stop loss and managed take profit targets, is used to determine whether the targets have been hit.",
"translations": [
{
"language": "ES",
"text": "El target rate es una tasa de referencia que puede afectar a las simulaciones y que, en combinación con la ubicación de los objetivos de stop loss gestionados y take profit gestionados, se utiliza para determinar si se han alcanzado los objetivos.",
"updated": 1629580668142
}
]
},
"paragraphs": [
{
@@ -143,4 +150,4 @@
"text": "As you see, flexibility is a key design feature in Superalgos."
}
]
}
}
@@ -1,7 +1,14 @@
{
"type": "Trigger Off Event",
"definition": {
"text": "The trigger-off event defines the situation in which the corresponding strategy shall be triggered-off. A strategy that is triggered-off releases the capital in reserve and makes it available to other strategies in the trading system."
"text": "The trigger-off event defines the situation in which the corresponding strategy shall be triggered-off. A strategy that is triggered-off releases the capital in reserve and makes it available to other strategies in the trading system.",
"translations": [
{
"language": "ES",
"text": "El evento trigger-off define la situación en la que se activará la estrategia correspondiente. Una estrategia que se activa libera el capital en reserva y lo pone a disposición de otras estrategias en el sistema de trading.",
"updated": 1629580571614
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Trigger On Event",
"definition": {
"text": "The trigger-on event defines the set of rules that need to be met for the corresponding strategy to be triggered on. A strategy that is triggered may use all the capital available to the trading system, and prevents other strategies in the system from triggering."
"text": "The trigger-on event defines the set of rules that need to be met for the corresponding strategy to be triggered on. A strategy that is triggered may use all the capital available to the trading system, and prevents other strategies in the system from triggering.",
"translations": [
{
"language": "ES",
"text": "El trigger-on event define el conjunto de reglas que deben cumplirse para que se active la estrategia correspondiente. Una estrategia que se activa puede utilizar todo el capital disponible para el sistema de trading y evita que se activen otras estrategias en el sistema.",
"updated": 1629580618624
}
]
},
"paragraphs": [
{
@@ -1,7 +1,14 @@
{
"type": "Trigger On",
"definition": {
"text": "Counts the periods since the last time a strategy was triggered on."
"text": "Counts the periods since the last time a strategy was triggered on.",
"translations": [
{
"language": "ES",
"text": "Cuenta los períodos desde la última vez que se activó una estrategia.",
"updated": 1629580287934
}
]
},
"paragraphs": [
{
@@ -4,7 +4,14 @@
"type": "Workspaces",
"definition": {
"text": "Workspaces are a powerful concept. They enable working on multiple settings in an orderly fashion.",
"updated": 1615893371936
"updated": 1615893371936,
"translations": [
{
"language": "ES",
"text": "Workspaces son un concepto poderoso. Permiten trabajar en múltiples entornos de forma ordenada.",
"updated": 1629579704727
}
]
},
"paragraphs": [
{
@@ -4,7 +4,14 @@
"type": "Simple Moving Average",
"definition": {
"text": "A simple moving average (SMA) calculates the average of a selected range of prices, usually closing prices, by the number of periods in that range.",
"updated": 1622686933380
"updated": 1622686933380,
"translations": [
{
"language": "ES",
"text": "Un simple moving average (SMA) calcula el promedio de un rango seleccionado de precios, generalmente precios de cierre, por el número de períodos en ese rango.",
"updated": 1629579640550
}
]
},
"paragraphs": [
{
@@ -0,0 +1,28 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 1,
"type": "Creating Your User Profile Tutorial",
"definition": {
"text": "This Tutorial walks you through the steps to create a User Profile and begin the journey to participating in Superalgos Governance.",
"updated": 1629146822189
},
"paragraphs": [
{
"style": "Title",
"text": "About This Tutorial"
},
{
"style": "List",
"text": "Workspace: Token Distribution Superalgos.",
"updated": 1629146723735
},
{
"style": "List",
"text": "Maintainer: @harrellbm (Telegram, and Discord)."
},
{
"style": "Text",
"text": ""
}
]
}
@@ -0,0 +1,33 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 2,
"type": "Tutorial Step - Better Together",
"definition": {
"text": "Welcome to Superalgos Governance! Today I will walk you through everything you need to know about creating a Superalgos User Profile and joining the Governance network!",
"updated": 1629164302622,
"icon": {
"name": "Charting-Space/chart-points",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "As a completely open source and collaborative project, Superalgos is not run by any singular set of people. ",
"updated": 1629164311647
},
{
"style": "Note",
"text": "Even the core team, who are dedicated to improving and maintaining Superalgos, do not directly control the path development will take. ",
"updated": 1629164322397
},
{
"style": "Text",
"text": "Instead, the governance system distributes decision making power across all register users by leveraging the SA token."
},
{
"style": "Text",
"text": ""
}
]
}
@@ -0,0 +1,28 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 3,
"type": "Tutorial Step - Make sure You’re Comfortable",
"definition": {
"text": "Before you jump into governance, it’s important you know what is being governed!",
"updated": 1629147485727,
"icon": {
"name": "Charting-Space/charting-space",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "We have got a lot of exciting things to talk about, but I want to make sure you can follow along easily. ",
"updated": 1629164474591
},
{
"style": "Callout",
"text": "If you haven't already, take some time to go through the Getting Started Tutorials."
},
{
"style": "Success",
"text": "There is no need to be an expert, but some general knowledge of the system will make your time in the Governance project much more productive."
}
]
}
@@ -0,0 +1,29 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 4,
"type": "Tutorial Step - One Token to Rule Them All",
"definition": {
"text": "Unlike some crypto currencies the SA token actually means something!",
"updated": 1629162158011,
"icon": {
"name": "design-space",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "The SA token is a BEP20 token hosted on the Binance Smart Chain (BSC). It represents your amount of investment in the Superalgos project and community. It is a way to reward and grow the Superalgos user base and development pool.",
"updated": 1629164803435
},
{
"style": "Success",
"text": "This means that the more you contribute to the project and help others, the more tokens you will earn!",
"updated": 1629164817915
},
{
"style": "Text",
"text": ""
}
]
}
@@ -0,0 +1,24 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 5,
"type": "Tutorial Step - With Tokens Comes Responsibility",
"definition": {
"text": "Holding tokens does more than just show commitment. SA tokens also confer governance power!",
"updated": 1629162449407,
"icon": {
"name": "workspace",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "The more tokens you hold the more influence you can have over the direction of the project. This means, by owning SA tokens, you hold the power to use those tokens to exert influence over what parts of the system will be developed and how the community will evolve.",
"updated": 1629165111109
},
{
"style": "Note",
"text": "This works in a cycle. The more you contribute, the more tokens you earn, the more say you have!"
}
]
}
@@ -0,0 +1,25 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 6,
"type": "Tutorial Step - A Mighty Meritocracy",
"definition": {
"text": "Superalgos does not reward freeloading! Real contributions to the project and community are what get rewarded with SA tokens and Governance power.",
"updated": 1629162653518,
"icon": {
"name": "crypto-exchange",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "The fancy word for this kind of project governance is meritocracy. In other words, the more you contribute to the improvement of Superalgos, and to the support of our community, the more governance power you earn to influence the future of the Superalgos project.",
"updated": 1629165463461
},
{
"style": "Note",
"text": "This is a collaboration! Only together can we continue to make Superalgos the game changer it is today no matter what the future may bring.",
"updated": 1629165548280
}
]
}
@@ -0,0 +1,24 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 7,
"type": "Tutorial Step - A Worthy Contribution",
"definition": {
"text": "No matter who you are, you can bring value to the Superalgos network!",
"updated": 1629162880545,
"icon": {
"name": "Market/market",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Success",
"text": "Each of us bring unique talents and experience into our work with Superalgos. Even if you are not a programmer or expert trader there is still ways for you to get involved and grow the project!",
"updated": 1629165838038
},
{
"style": "Text",
"text": "One of the first contributions you can make to the project is getting involved in governance itself. The network of users guiding Superalgos is an integral part of the success of our open collaboration. You bring value to the network just by being a part of it!"
}
]
}
@@ -0,0 +1,25 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 8,
"type": "Tutorial Step - What’s in a Profile?",
"definition": {
"text": "So what are we waiting for? Let’s get started! To participate in Governance you will first need a User Profile.",
"updated": 1629163040597,
"icon": {
"name": "Charting-Space/chart-points",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "Your profile is set up just like the rest of the Superalgos system. It is a hierarchy of nodes. Only this hierarchy defines how you intend to use the Token Power you have earned or is delegated to you by other users. ",
"updated": 1629165991225
},
{
"style": "Note",
"text": "By channelling your token power you help decide what parts of the system will be incentivised for further development and who will be rewarded for the community roles they have played.",
"updated": 1629166027369
}
]
}
@@ -0,0 +1,29 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 9,
"type": "Tutorial Step - Program Participation",
"definition": {
"text": "How you use your Token Power is defined within a number of different Programs within your profile hierarchy.",
"updated": 1629163374967,
"icon": {
"name": "Charting-Space/chart-points",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "These programs help organize the types of development and community relationships you want to reward. ",
"updated": 1629166399952
},
{
"style": "Note",
"text": "For instance, the Claims Program lets you present claims for the work you’ve done. While the Support Program lets you thank other Superalgos users that have helped you with technical support. ",
"updated": 1629166416422
},
{
"style": "Text",
"text": "We’ll cover all these and other programs in detail once you have a working profile!"
}
]
}
@@ -0,0 +1,25 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 10,
"type": "Tutorial Step - Where is all Begins",
"definition": {
"text": "Here we are at the head of the governance project. Let’s get that profile created!",
"updated": 1629163572836,
"icon": {
"name": "Charting-Space/dashboard",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Callout",
"text": "Click the Add Profile Constructor button.",
"updated": 1629163599518
},
{
"style": "Text",
"text": "Now position the resulting Profile Constructor node where it is easy to see.",
"updated": 1629163626525
}
]
}
@@ -0,0 +1,30 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 11,
"type": "Tutorial Step - Profile in a Heartbeat",
"definition": {
"text": "The Profile Constructor is the device you will use to set up your profile. ",
"updated": 1629163751173,
"icon": {
"name": "under-construction",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Text",
"text": "Not only that but it will create a unique Binance Smart Chain wallet that is connected with your profile. We call it your Governance Address.",
"updated": 1629166742408
},
{
"style": "Note",
"text": "This means that you will not be able to use any existing wallet addresses you may own, but will create a new one. ",
"updated": 1629166737533
},
{
"style": "Text",
"text": "Your Governance Address will allow you to receive the SA tokens you earn. Superalgos will also read the balance of this address to become aware of the number of SA tokens you hold, and assign your profile an equivalent amount of Token Power.",
"updated": 1629166705049
}
]
}
@@ -0,0 +1,33 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 12,
"type": "Tutorial Step - Pump that Heartbeat!",
"definition": {
"text": "Now let’s configure that constructor! ",
"updated": 1629167048288,
"icon": {
"name": "Time/time-machine",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Callout",
"text": "Click the configuration option and type your GitHub username under the username properly.",
"updated": 1629167062088
},
{
"style": "Text",
"text": "It should look something like this:"
},
{
"style": "Json",
"text": "{\n \"githubUsername\": \"My Awesome Username\"\n}",
"updated": 1629167126327
},
{
"style": "Text",
"text": ""
}
]
}
@@ -0,0 +1,33 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 12,
"type": "Tutorial Step - Pump that Heartbeat!",
"definition": {
"text": "Now let’s configure that Profile Constructor!",
"updated": 1629167519082,
"icon": {
"name": "Time/time-machine",
"project": "Foundations"
}
},
"paragraphs": [
{
"style": "Callout",
"text": "Click the configuration option and type your GitHub username under the username properly.",
"updated": 1629167062088
},
{
"style": "Text",
"text": "It should look something like this:"
},
{
"style": "Json",
"text": "{\n \"githubUsername\": \"My Awesome Username\"\n}",
"updated": 1629167126327
},
{
"style": "Text",
"text": ""
}
]
}
@@ -0,0 +1,23 @@
{
"tutorial": "Creating Your User Profile Tutorial",
"pageNumber": 13,
"type": "Tutorial Step - Oh so Shiny",
"definition": {
"text": "Write a summary for this tutorial page."
},
"paragraphs": [
{
"style": "Text",
"text": "We are almost there. Now click create user profile and watch the magic happen. That’s right, you just created your profile!",
"updated": 1629167761539
},
{
"style": "Text",
"text": "While we didn’t have to break a sweat making your profile, some pretty amazing things happened behind the scenes. The constructor just generated your user profile, and unique SA Token Governance address. A cryptographic message with your GitHub.com username has been signed with the private key corresponding to the address just generated. This message will be stored in your User Profile so that we may authenticate it comes from you once you submit your profile as a plugin in the Governance Project."
},
{
"style": "Text",
"text": "What this means is that your profile, and its associated token address, can only be accessed and changed by you!"
}
]
}
@@ -5,30 +5,40 @@
"definition": {
"text": "Let’s build the mother of all trading strategies: The Moving Average Cross!",
"icon": {
"name": "Tutorial/tutorial",
"name": "Tutorial\\tutorial",
"project": "Foundations"
},
"updated": 1614275495850,
"updated": 1629342747241,
"translations": [
{
"language": "DE",
"text": "Lass uns die Mutter aller Handelsstrategien aufbauen: Die Moving Average Überkreuzung!",
"updated": 1622970055812,
"style": "Definition"
},
{
"language": "ES",
"text": "Construyamos la madre de todas las estrategias trading: The Moving Average Cross",
"updated": 1629342995750
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "For this tutorial I assume that",
"updated": 1614240501976,
"text": "For this tutorial I assume that:",
"updated": 1629342738424,
"translations": [
{
"language": "DE",
"text": "Für dieses Lernprogramm gehe ich davon aus, dass",
"updated": 1622970071369,
"style": "Text"
},
{
"language": "ES",
"text": "Para este tutorial supongo que:",
"updated": 1629343108610
}
]
},
@@ -41,8 +51,14 @@
"text": "du das Willkommens-Tutorial im Workspace \"Erste Schritte\" absolviert haben",
"updated": 1622970086389,
"style": "List"
},
{
"language": "ES",
"text": "Has hecho el Welcome Tutorial en el Getting Started Workspace",
"updated": 1629343127301
}
]
],
"updated": 1629342770748
},
{
"style": "List",
@@ -53,32 +69,48 @@
"text": "du dich sicher im Workspace und in den Charts bewegen kannst.",
"updated": 1622970109192,
"style": "List"
},
{
"language": "ES",
"text": "Te sientes cómodo moviéndote por el Workspace y los Charts",
"updated": 1629343147093
}
]
],
"updated": 1629342792390
},
{
"style": "List",
"text": "You have a basic understanding about what is a Trading Bot and a strategy",
"updated": 1614275543824,
"updated": 1629342812080,
"translations": [
{
"language": "DE",
"text": "du hast ein grundlegendes Verständnis davon, was ein Trading Bot und eine Trading Strategie ist",
"updated": 1622970162593,
"style": "List"
},
{
"language": "ES",
"text": "Tienes un conocimiento básico sobre lo que es un Trading Bot y una estrategia",
"updated": 1629343167648
}
]
},
{
"style": "Note",
"text": "We will build a bot to backtest a strategy based on Simple Moving Average Cross between SMA50 and SMA200 on 4h TF, a classic!",
"updated": 1622980039332,
"updated": 1629342831236,
"translations": [
{
"language": "DE",
"text": "Wir werden einen Bot bauen, der auf eine Simple Moving Average Überkreuzung zwischen SMA50 und SMA200 auf 4h TF(Time Frame) basierende Strategie backtestet, ein Klassiker!",
"updated": 1622980080284,
"style": "Note"
},
{
"language": "ES",
"text": "Construiremos un bot para probar una estrategia basada en Simple Moving Average Cross entre SMA50 y SMA200 en 4h TF, ¡un clásico!",
"updated": 1629343206412
}
]
},
@@ -4,9 +4,9 @@
"type": "Tutorial Step - Look around",
"definition": {
"text": "Workspaces can be changed!",
"updated": 1614241100778,
"updated": 1629344688461,
"icon": {
"name": "Layer/layer",
"name": "Layer\\layer",
"project": "Foundations"
},
"translations": [
@@ -15,6 +15,11 @@
"text": "Workspaces können angepasst werden!",
"updated": 1622977673407,
"style": "Definition"
},
{
"language": "ES",
"text": "Workspaces pueden ser cambiados",
"updated": 1629344801370
}
]
},
@@ -22,26 +27,36 @@
{
"style": "Text",
"text": "I arranged the workspace in a slightly different way compared to Getting Started. It's a good practice to customize the workspace to keep it tidy and clean. Remember that every hierarchy, node or offspring can impact on your machine resources.",
"updated": 1614241304126,
"updated": 1629344708619,
"translations": [
{
"language": "DE",
"text": "Ich habe den Workspace im Vergleich zu Getting Started (\"Erste Schritte\") etwas anders angeordnet. Es ist eine gute Praxis, den Workspace anzupassen, um ihn aufgeräumt und sauber zu halten. Denke daran, dass jede Hierarchie, jeder Knoten und jeder Nachfolgende Auswirkungen auf deine Maschinenressourcen haben kann.",
"updated": 1622977620392,
"style": "Text"
},
{
"language": "ES",
"text": "Arreglé el workspace de una manera ligeramente diferente en comparación con Getting Started. Es una buena práctica personalizar el workspace para mantenerlo ordenado y limpio. Recuerda que cada jerarquía, nodo o descendencia puede afectar los recursos de tu máquina.",
"updated": 1629344864911
}
]
},
{
"style": "Success",
"text": "Have a look around, right click on empty space and explore the Workspace I arranged for you!",
"updated": 1614334045360,
"updated": 1629344734628,
"translations": [
{
"language": "DE",
"text": "Schau dich um, klicke mit der rechten Maustaste auf eine leere Fläche und erkunde den Workspace, den ich für dich eingerichtet habe!",
"updated": 1622977643971,
"style": "Success"
},
{
"language": "ES",
"text": "Echa un vistazo, haga clic derecho en el espacio vacío y explore el Workspace. ¡Lo arreglé para ti!",
"updated": 1629344896872
}
]
},
@@ -5,7 +5,7 @@
"definition": {
"text": "Not only Workspaces can be modified",
"icon": {
"name": "Data/data-mine",
"name": "Data\\data-mine",
"project": "Foundations"
},
"updated": 1614241455319,
@@ -15,6 +15,11 @@
"text": "Nicht nur Workspaces können modifiziert werden.",
"updated": 1622977759915,
"style": "Definition"
},
{
"language": "ES",
"text": "No solo Workspaces se pueden modificar",
"updated": 1629346887546
}
]
},
@@ -29,6 +34,11 @@
"text": "SA ist sehr modular und kann so angeordnet werden, wie wir es für unsere Bedürfnisse bevorzugen.",
"updated": 1622977780236,
"style": "Text"
},
{
"language": "ES",
"text": "SA es muy modular y se puede organizar de la manera que prefiramos para nuestras necesidades.",
"updated": 1629347317411
}
]
},
@@ -41,6 +51,11 @@
"text": "Ich habe für dich einen sehr einfachen Workspace mit einer neuen Data Mine vorbereitet und die Knoten angeordnet, wobei ich alles gelöscht habe, was ich für dieses Tutorial nicht benötige.",
"updated": 1622977811209,
"style": "Text"
},
{
"language": "ES",
"text": "Te preparé un muy básico Workspace con un nuevo Data Mine y organize los nodos eliminando todo lo que no necesito para este tutorial.",
"updated": 1629347385771
}
]
},
@@ -53,6 +68,11 @@
"text": "In SA können Data Mines hinzugefügt und entfernt werden, aber die auf der Festplatte gespeicherten Daten werden nicht gelöscht, wenn du einen Indikator entfernst!",
"updated": 1622977843713,
"style": "Success"
},
{
"language": "ES",
"text": "En SA, las minas de datos se pueden agregar y eliminar, pero los datos guardados en su disco duro no se eliminarán si eliminas un indicador.",
"updated": 1629347666344
}
]
},
@@ -5,7 +5,7 @@
"definition": {
"text": "Let's build the mother of all strategies!",
"icon": {
"name": "Strategy/strategy",
"name": "Strategy\\strategy",
"project": "Foundations"
},
"updated": 1614241902261,
@@ -15,6 +15,11 @@
"text": "Lass uns die Mutter aller Strategien erstellen!",
"updated": 1622977892890,
"style": "Definition"
},
{
"language": "ES",
"text": "¡Construyamos la madre de todas las estrategias!",
"updated": 1629347747877
}
]
},
@@ -29,6 +34,11 @@
"text": "Um eine Strategie backtesten zu können, müssen wir sie erst einmal schreiben oder klar im Kopf haben. Auf folgenden Eckpfeilern basiert unser Test:",
"updated": 1622979087886,
"style": "Text"
},
{
"language": "ES",
"text": "Para realizar una prueba retrospectiva de una estrategia, primero debemos escribirla o tenerla clara en nuestra mente. Así que estas son las piedras angulares en las que se basa nuestra prueba:",
"updated": 1629347848333
}
]
},
@@ -41,6 +51,11 @@
"text": "Strategie verwendet SMA50 und SMA200",
"updated": 1622977962657,
"style": "List"
},
{
"language": "ES",
"text": "Strategy usa SMA50 y SMA200",
"updated": 1629347862168
}
]
},
@@ -53,6 +68,11 @@
"text": "Die Strategie basiert auf 4h TF (Time Frame)",
"updated": 1622979509680,
"style": "List"
},
{
"language": "ES",
"text": "Strategy está basado en 4H TF",
"updated": 1629347891997
}
]
},
@@ -65,6 +85,11 @@
"text": "Der Bot wird das Asset kaufen, wenn der SMA50 den SMA200 nach oben kreuzt",
"updated": 1622978113525,
"style": "List"
},
{
"language": "ES",
"text": "El bot comprará el asset cuando SMA50 cruzar hasta SMA200",
"updated": 1629347952235
}
]
},
@@ -77,6 +102,11 @@
"text": "Stop Loss wird auf 20% vom Einstiegspunkt gesetzt",
"updated": 1622978127244,
"style": "List"
},
{
"language": "ES",
"text": "Stop Loss está fijado en 20% desde la entrada",
"updated": 1629348020213
}
]
},
@@ -89,6 +119,11 @@
"text": "Take Profit wird auf 100% oder auf SMA50 kreuzt SMA200 nach unten gesetzt",
"updated": 1622978244002,
"style": "List"
},
{
"language": "ES",
"text": "Take Profit está fijado en 100% o en SMA50 cruzar abajo SMA200",
"updated": 1629348082752
}
]
}
@@ -5,7 +5,7 @@
"definition": {
"text": "Trading System is already set up. Let's have a look!",
"icon": {
"name": "Trading/trading-system-reference",
"name": "Trading\\trading-system-reference",
"project": "Foundations"
},
"updated": 1614242955916,
@@ -15,6 +15,11 @@
"text": "Das Trading System ist bereits aufgesetzt. Lass es uns anschauen!",
"updated": 1622978283268,
"style": "Definition"
},
{
"language": "ES",
"text": "Trading System ya está configurado. ¡Echemos un vistazo!",
"updated": 1629348173186
}
]
},
@@ -29,6 +34,11 @@
"text": "ie Strategie ist bereits umgesetzt. Schauen wir sie uns einmal an, um sie zu verstehen!",
"updated": 1622978294304,
"style": "Text"
},
{
"language": "ES",
"text": "La estrategia ya está desplegada. ¡Así que echemos un vistazo para entenderlo!",
"updated": 1629348191210
}
]
},
@@ -41,6 +51,11 @@
"text": "Wie du sehen kannst, hat ein Tradingsystem zwei Hauptnachfolger:",
"updated": 1622978319793,
"style": "Text"
},
{
"language": "ES",
"text": "Como puedes ver, un Trading System tiene 2 descendientes principales:",
"updated": 1629348227357
}
]
},
@@ -54,6 +69,11 @@
"text": "Dynamic Indicators (\"Dynamische Indikatoren\"): Damit kannst du On-The-Fly-Indikatoren erstellen",
"updated": 1622978351655,
"style": "List"
},
{
"language": "ES",
"text": "Dynamic Indicators: Esto te permite crear indicadores sobre la marcha",
"updated": 1629348275874
}
]
},
@@ -67,6 +87,11 @@
"text": "Trading Strategy (\"Handelsstrategie\"): Hier definieren wir Parameter, Bedingungen und Formeln für unsere Strategie",
"updated": 1622978372386,
"style": "List"
},
{
"language": "ES",
"text": "Trading Strategy: Es donde definimos parámetros, condiciones y fórmulas para nuestra estrategia.",
"updated": 1629348244296
}
]
},
@@ -79,6 +104,11 @@
"text": "Dieses Tutorial behandelt keine Definitionen oder Konzepte, die in SA verwendet werden. In diesem Tutorial geht es nur darum, wie man eine Strategie einsetzt!",
"updated": 1622978385419,
"style": "Success"
},
{
"language": "ES",
"text": "Este tutorial no cubre definiciones o conceptos usados ​​en SA. ¡Este tutorial solo trata sobre cómo implementar una estrategia!",
"updated": 1629348296182
}
]
}
@@ -15,6 +15,11 @@
"text": "Trigger Stage ist unser Talent Scout.",
"updated": 1622978455848,
"style": "Definition"
},
{
"language": "ES",
"text": "Trigger Stagees es nuestro talento scout",
"updated": 1629348587860
}
]
},
@@ -29,6 +34,11 @@
"text": "Unsere Strategie basiert auf dem SMA-Kreuz und in diesem Knoten können wir den Bot anweisen, nach Bedingungen zu suchen, die erfüllt sein müssen, um einen Handel zu tätigen.",
"updated": 1622978530689,
"style": "Text"
},
{
"language": "ES",
"text": "Nuestra estrategia se basa en el cruce de SMA y es en este nodo donde podemos instruir al bot para que busque las condiciones que deben cumplirse para realizar una operación.",
"updated": 1629348884906
}
]
},
@@ -41,6 +51,11 @@
"text": "In dieser Phase geht es darum, den Markt zu überprüfen und zu entscheiden, ob die Bedingungen einen Handel wert sind oder nicht!",
"updated": 1622978559675,
"style": "Important"
},
{
"language": "ES",
"text": "¡Esta etapa se trata de verificar el mercado y decidir si algunas condiciones valen la pena o no!",
"updated": 1629348903247
}
]
},
@@ -54,6 +69,11 @@
"text": "Werfen wir einen Blick auf seine drei Nachfolger und ich zeige dir ein paar kleine Tricks, um die Strategie schnellstmöglich zu implementieren!",
"updated": 1622978601078,
"style": "Text"
},
{
"language": "ES",
"text": "¡Echemos un vistazo a sus 3 descendientes y te muestro algunos pequeños trucos para implementar la estrategia de la manera más rápida posible!",
"updated": 1629348921004
}
]
}
@@ -15,6 +15,11 @@
"text": "Reserviere Geldmittel!",
"updated": 1622978638588,
"style": "Definition"
},
{
"language": "ES",
"text": "¡Reserva algunos fondos!",
"updated": 1629349159115
}
]
},
@@ -29,6 +34,11 @@
"text": "Beim Ereignis Trigger On geht es darum, deine Mittel zu reservieren (zu sperren) und sie dem Bot zur Verfügung zu stellen.",
"updated": 1622981206455,
"style": "Text"
},
{
"language": "ES",
"text": "El evento Trigger On consiste en reservar (bloquear) sus fondos y ponerlos a disposición del bot.",
"updated": 1629349408557
}
]
},
@@ -45,6 +55,11 @@
"text": "Was ich tun muss, ist:",
"updated": 1622978676342,
"style": "Text"
},
{
"language": "ES",
"text": "Lo que necesito hacer es:",
"updated": 1629349429401
}
]
},
@@ -57,6 +72,11 @@
"text": "Definiere den TF (Time Frame)",
"updated": 1622978697311,
"style": "List"
},
{
"language": "ES",
"text": "Definir el TF",
"updated": 1629349443558
}
]
},
@@ -69,6 +89,11 @@
"text": "Definiere das SMA50/200 Kreuz",
"updated": 1622978711889,
"style": "List"
},
{
"language": "ES",
"text": "Definir el SMA50/200 cross",
"updated": 1629349524087
}
]
},
@@ -81,6 +106,11 @@
"text": "Zur Definition, verwende ich zwei Bedingungen:",
"updated": 1622981248271,
"style": "Text"
},
{
"language": "ES",
"text": "Para definir una cruz utilizo 2 condiciones:",
"updated": 1629351309083
}
]
},
@@ -15,6 +15,11 @@
"text": "Wenn du keine Bedingung benötigst setze es einfach auf „False“ oder „True“!",
"updated": 1622978946854,
"style": "Definition"
},
{
"language": "ES",
"text": "Si no necesitas una condición, configúrela en False o True!",
"updated": 1629352241171
}
]
},
@@ -29,6 +34,11 @@
"text": "Für meinen Backtest benötige ich keine Trigger Off Bedingung, also schreibe ich einfach False in den Javascript-Code",
"updated": 1622978973861,
"style": "Text"
},
{
"language": "ES",
"text": "Para mi backtest no necesito un Trigger Off condición, así que solo escribo false en codigo Javascript",
"updated": 1629354481694
}
]
},
@@ -42,6 +52,11 @@
"text": "Denke daran, dass Bedingungen nur True oder False sein können. Wenn ich Javascript-Code innerhalb dieser Art von Knoten schreibe, müssen sie True oder False auswerten, weil das, was ich schreibe, im Wesentlichen ein Test ist.",
"updated": 1622978923884,
"style": "Success"
},
{
"language": "ES",
"text": "Recuerda que Conditions puede ser solo True o False. Cuando escribo código Javascript dentro de este tipo de nodos, deben evaluar True o False porque esencialmente lo que estoy escribiendo es una prueba.",
"updated": 1629354487276
}
]
}
@@ -15,6 +15,11 @@
"text": "Zeit, um Position zu beziehen!",
"updated": 1622979146522,
"style": "Definition"
},
{
"language": "ES",
"text": "Tiempo para tomar Position!",
"updated": 1629355595189
}
]
},
@@ -29,6 +34,11 @@
"text": "In diesem Knoten verwende ich den gleichen Trick wie beim Trigger Off Event (Ereignis), erzwinge aber in diesem Fall den Wert True. Ich habe bereits im Trigger On Event definiert, was meine Bedingungen sind. In diesem Knoten kann ich also einfach die beiden Bedingungen kopieren und auf True setzen.",
"updated": 1622981314446,
"style": "Text"
},
{
"language": "ES",
"text": "En este nodo utilizo el mismo truco utilizado para el Trigger Off Event pero en este caso obligándolo a True.Ya lo definí en el Trigger On Event cuales son mis condiciones. Entonces en este nodo puedo simplemente copiar las dos condiciones o configurarlo en True.",
"updated": 1629355939657
}
]
},
@@ -41,6 +51,11 @@
"text": "Wenn ich mehr Bedingungen benötige, kann ich sie natürlich nach meinen Bedürfnissen hinzufügen oder ändern!",
"updated": 1622979260265,
"style": "Success"
},
{
"language": "ES",
"text": "¡Por supuesto, si necesito más condiciones, puedo agregarlas o modificarlas según mis necesidades!",
"updated": 1629355966149
}
]
},
@@ -53,6 +68,11 @@
"text": "Cool. Meine Definitionen sind festgelegt. Es ist an der Zeit, zur Open Stage überzugehen!",
"updated": 1622981356171,
"style": "Note"
},
{
"language": "ES",
"text": "Súper. Mis definiciones iniciales están establecidas. ¡Es hora de pasar al Open Stage!",
"updated": 1629356060233
}
]
}
@@ -5,7 +5,7 @@
"definition": {
"text": "The Open Stage is where bot take position!",
"icon": {
"name": "Open/open-stage",
"name": "Open\\open-stage",
"project": "Foundations"
},
"updated": 1614260398081,
@@ -15,6 +15,11 @@
"text": "Die Open Stage ist der Zeitpunkt, an dem der Bot die Position einnimmt!",
"updated": 1622979315892,
"style": "Definition"
},
{
"language": "ES",
"text": "El Open Stage es donde el bot toma posición!",
"updated": 1629356240122
}
]
},
@@ -29,6 +34,11 @@
"text": "Die Strategie, die ich backtesten möchte, basiert auf 4h TF und die Strategie ist Long (steigende Kurse). Das bedeutet, dass der Bot das Asset kaufen wird, um es später zu verkaufen (zu einem besseren Preis, wie wir hoffen!). Um die Dinge einfach zu halten, muss ich nur den TF im Target Rate-Knoten angeben, indem ich meinen vollen Saldo im Target Size in Quoted Asset verwende.",
"updated": 1622979336945,
"style": "Text"
},
{
"language": "ES",
"text": "La estrategia que quiero hacer backtesting se basa en 4h TF y la estrategia es Long. Esto significa que el bot Buy el asset para después Sell (¡a un mejor precio esperamos!). Para simplificar las cosas, todo lo que tengo que hacer es indicar el TF en el nodo Target Rate usando todo mi saldo en el Target Size en Quoted Asset.",
"updated": 1629356415752
}
]
},
@@ -42,6 +52,11 @@
"text": "Wenn unser Markt BTC/USDT ist, dann ist das Quoted Asset USDT und Base Asset ist BTC.",
"updated": 1622979556680,
"style": "Success"
},
{
"language": "ES",
"text": "Si nuestro mercado es BTC/USDT entonces la Quoted Asset is USDT y Base Asset es BTC",
"updated": 1629356454601
}
]
}
@@ -15,6 +15,12 @@
"text": "Gewinn mitnehmen (Take Profit) oder einen Verlust begrenzen (Stop Loss)?!",
"updated": 1622979661677,
"style": "Definition"
},
{
"language": "ES",
"text": "El Manage Stagees donde el bot comprueba si tiene que hacer Take Profit o un Stop Loss",
"updated": 1629356619813,
"style": "Definition"
}
]
},
@@ -29,6 +35,12 @@
"text": "In dieser Phase prüft der Bot, ob der Preis Take Profit (TP) oder Stop Loss (SL) erreicht hat. Die anfänglichen Bedingungen für meine Strategie waren, einen SL bei 20% vom Einstieg zu setzen und einen TP bei 100% oder wenn MA50 unter MA200 kreuzt.",
"updated": 1622979639862,
"style": "Text"
},
{
"language": "ES",
"text": "En esta etapa, el bot comprueba si el precio ha llegado a Take Profit (TP) o Stop Loss (SL). Las condiciones iniciales para mi estrategia fueron establecer un SL al 20% desde la entrada y un TP al 100% o cuando MA50 cruza por debajo de MA200.",
"updated": 1629356685676,
"style": "Text"
}
]
},
@@ -60,6 +72,11 @@
"text": "Die Take Profit Formel ist ein wenig aufwendiger:",
"updated": 1622979702092,
"style": "Text"
},
{
"language": "ES",
"text": "La fórmula Take Profit es un poco más elaborada:",
"updated": 1629423638424
}
]
},
@@ -5,7 +5,7 @@
"definition": {
"text": "The Close Stage is in charge of closing the trade",
"icon": {
"name": "Close/close-stage",
"name": "Close\\close-stage",
"project": "Foundations"
},
"updated": 1614261551174,
@@ -15,6 +15,11 @@
"text": "Die Close Stage ist für das Schließen des Trades zuständig.",
"updated": 1622979775474,
"style": "Definition"
},
{
"language": "ES",
"text": "El Close Stage se encarga de cerrar el trade",
"updated": 1629576232311
}
]
},
@@ -29,6 +34,11 @@
"text": "In der vorherigen Phase (der Manage Stage) prüft der Bot, ob der aktuelle Preis den SL oder den TP getroffen hat. Sobald eines dieser beiden Ereignisse eingetreten ist, übernimmt die Close Stage die Aufgabe, die Position zu schließen. Die Funktionsweise ist sehr ähnlich wie bei der Open Stage. Der Bot muss wissen, auf welche Kerze er schauen soll.",
"updated": 1622979799896,
"style": "Text"
},
{
"language": "ES",
"text": "En la etapa anterior (el Manage Stage) bot está comprobando si el precio actual ha alcanzado el SL o el TP. Una vez que uno de estos dos eventos ha sido alcanzado, entonces el Close Stage se encarga de cerrar el trade. La forma en que funciona es muy similar al Open Stage. El bot necesita saber qué vela debe verse",
"updated": 1629576335495
}
]
},
@@ -45,6 +55,11 @@
"text": "Im Gegensatz zur Open Stage verkaufen wir hier das Asset, daher benötigen wir eine Market Sell Order und der Bot verkauft das quotierte Asset.",
"updated": 1622979827422,
"style": "Text"
},
{
"language": "ES",
"text": "Y obviamente a diferencia del Open Stage, aquí nosotros Sell el asset así que necesitamos un Market Sell Order Y lo que vende bot es el Quoted asset",
"updated": 1629576513796
}
]
},
@@ -5,7 +5,7 @@
"definition": {
"text": "Strategy is defined!",
"icon": {
"name": "Announcement/announcement",
"name": "Announcement\\announcement",
"project": "Foundations"
},
"updated": 1614262144926,
@@ -15,6 +15,12 @@
"text": "Strategie definiert!",
"updated": 1622980119217,
"style": "Definition"
},
{
"language": "ES",
"text": "¡ Strategy está definida!",
"updated": 1629357095005,
"style": "Definition"
}
]
},
@@ -29,6 +35,12 @@
"text": "Wie du gesehen hast, ist die Implementierung einer einfachen Strategie eine Sache von wenigen Zeilen Code!",
"updated": 1622980130290,
"style": "Text"
},
{
"language": "ES",
"text": "Es cuestión de unas pocas líneas de código.",
"updated": 1629576702851,
"style": "Text"
}
]
},
@@ -42,6 +54,12 @@
"text": "Beachte dies, um korrekt mit Base und Quoted Asset umzugehen. Base ist oben, Quoted ist unten! In unserem Fall BTC/USD ist also BTC das Basis-Asset, während USDT das quotierte Asset ist.",
"updated": 1622980143220,
"style": "Success"
},
{
"language": "ES",
"text": "Ten esto en cuenta para tratar correctamente Base and Quoted Asset. Base está en la cima, Quoted está en el fondo! Entonces en nuestro caso BTC / USD tenemos BTC es el Base Asset mientras que USDT es el Quoted Asset",
"updated": 1629357672381,
"style": "Success"
}
]
},
@@ -55,6 +73,12 @@
"text": "Das ändert sich nicht, wenn du Short gehst. Wenn die Strategie Short ist, wird der Bot in der Eröffnungsphase das Basis-Asset verkaufen und es später mit dem quotierten Asset zurückkaufen!",
"updated": 1622980155348,
"style": "Warning"
},
{
"language": "ES",
"text": "No cambia si te vas Short. Si la estrategia es Short luego en el Open Stage Bot venderá el Base Asset y luego volver a comprarlo usando Quoted Asset!",
"updated": 1629357633755,
"style": "Warning"
}
]
}
@@ -5,7 +5,7 @@
"definition": {
"text": "Chances are you already have some data mined!",
"icon": {
"name": "Data/data-tasks",
"name": "Data\\data-tasks",
"project": "Foundations"
},
"updated": 1614267263084,
@@ -15,6 +15,11 @@
"text": "Eventuell hast du bereits ein paar Daten gemined!",
"updated": 1622980204621,
"style": "Definition"
},
{
"language": "ES",
"text": "¡Lo más probable es que ya tengas algunos datos extraídos!",
"updated": 1629576816892
}
]
},
@@ -29,6 +34,11 @@
"text": "Wenn du das Intro-Tutorial gemacht hast, dann hast du wahrscheinlich schon einige Daten geschürft. Allerdings habe ich einen neuen Indikator hinzugefügt, der in der Anfangskonfiguration nicht vorhanden ist. Führe also bitte die Data Mines aus (\"Run\") und warte, bis sie zu 100% fertig sind.",
"updated": 1622980292728,
"style": "Text"
},
{
"language": "ES",
"text": "Si has hecho la intro Tutorial entonces probablemente ya hayas extraído algunos datos. Pero agregué un nuevo indicador que no está presente en la configuración inicial. Así que por favor Run los data Mines Y espera hasta que estén 100% listos.",
"updated": 1629576956473
}
]
},
@@ -42,6 +52,11 @@
"text": "Stelle sicher, dass unter Sparta Data Mine Tasks der neu hinzugefügte Indikator Simple Moving Average zu 100% aktualisiert ist.",
"updated": 1622980304913,
"style": "Important"
},
{
"language": "ES",
"text": "Asegúrate de que debajo Sparta Data Mine Tasks el indicador recién agregado Simple Moving Average está 100% actualizado.",
"updated": 1629577044677
}
]
},
@@ -55,6 +70,11 @@
"text": "Sobald alle Indikatoren 100%ig sind, kannst du die Data Mines stoppen und Ressourcen für den Backtest sparen.",
"updated": 1622980322182,
"style": "Success"
},
{
"language": "ES",
"text": "Ya al 100%, puedes detener los Data Mines y ahorrar recursos para el backtest.",
"updated": 1629577393595
}
]
}
@@ -15,6 +15,11 @@
"text": "Stelle sicher, dass alle Parameter korrekt sind!",
"updated": 1622980368660,
"style": "Definition"
},
{
"language": "ES",
"text": "¡Asegurarte que los Parameters están en su lugar!",
"updated": 1629577782178
}
]
},
@@ -29,6 +34,11 @@
"text": "Bevor du den Backtest ausführst, stelle sicher, dass der Knoten Trading Parameters konsistente Daten hat. Ich habe bereits alles für dich vorbereitet, aber nimm dir etwas Zeit und beachte, dass:",
"updated": 1622980410674,
"style": "Text"
},
{
"language": "ES",
"text": "Antes de ejecutar el backtest, asegúrese de que el Trading Parameters nodo tiene datos consistentes. Ya preparé todo para ti, pero tómate un tiempo y fíjate que:",
"updated": 1629577823477
}
]
},
@@ -41,6 +51,11 @@
"text": "Session Base Asset auf 0 eingestellt ist",
"updated": 1622980449763,
"style": "List"
},
{
"language": "ES",
"text": "Session Base Asset está establecido en 0",
"updated": 1629577840744
}
]
},
@@ -54,6 +69,11 @@
"text": "Session Quoted Asset auf 1000 eingestellt ist (das sind in diesem Fall 1000$ USDT)",
"updated": 1622980491671,
"style": "List"
},
{
"language": "ES",
"text": "Session Quoted Assetestá establecido en 1000 (es decir, 1000 $ USDT en este caso)",
"updated": 1629577866359
}
]
},
@@ -67,6 +87,11 @@
"text": "Slippage auf 0 gesetzt ist, da ich kleine Beträge backteste und ich davon ausgehen kann, dass die Aufträge ohne Slippage ausgeführt werden",
"updated": 1622980519600,
"style": "List"
},
{
"language": "ES",
"text": "Slippage se establece en 0 porque estoy probando pequeñas cantidades y puedo asumir que los pedidos se llenan sin slippage",
"updated": 1629577911905
}
]
},
@@ -80,6 +105,11 @@
"text": "Bist du bereit? Führe (\"Run\") den Backtest aus!",
"updated": 1622980556540,
"style": "Important"
},
{
"language": "ES",
"text": "¿Estás listo? ¡Ejecuta el backtest!",
"updated": 1629578196637
}
]
}
@@ -15,6 +15,11 @@
"text": "Zeit sich die Charts anzuschauen!",
"updated": 1622980596813,
"style": "Definition"
},
{
"language": "ES",
"text": "¡Es hora de mirar el gráfico!",
"updated": 1629578259488
}
]
},
@@ -29,6 +34,11 @@
"text": "Wenn der Backtest beendet ist, halte ich die gesamte Hierarchie über den Knoten Testing Trading Tasks an. Erweitere den Knoten und klicke auf Stop All.",
"updated": 1622980659088,
"style": "Text"
},
{
"language": "ES",
"text": "Cuando finaliza el backtest, detengo toda la jerarquía del nodo Testing Trading Tasks. Expande el nodo y has clic en Stop All.",
"updated": 1629578317859
}
]
},
@@ -41,6 +51,11 @@
"text": "Denk daran, dass es eine gute Praxis ist, Hierarchien zusammengeklappt zu halten und nicht benötigte Aufgaben zu stoppen, um Ressourcen zu sparen!",
"updated": 1622980636929,
"style": "Success"
},
{
"language": "ES",
"text": "Recuerda que es una buena práctica mantener las jerarquías colapsadas y detener las tareas inútiles para ahorrar recursos.",
"updated": 1629578351656
}
]
},
@@ -5,7 +5,7 @@
"definition": {
"text": "Enjoy your backtest!",
"icon": {
"name": "Charting-space/charting-space",
"name": "Charting-Space\\charting-space",
"project": "Foundations"
},
"updated": 1614269880685,
@@ -15,6 +15,11 @@
"text": "Viel Spaß mit deinem Backtest!",
"updated": 1622980702656,
"style": "Definition"
},
{
"language": "ES",
"text": "¡Disfruta tu backtest!",
"updated": 1629578516025
}
]
},
@@ -29,6 +34,11 @@
"text": "Jetzt ist es an der Zeit, in den Charting Space zu wechseln und (falls noch nicht geschehen) starte:",
"updated": 1622980744641,
"style": "Text"
},
{
"language": "ES",
"text": "Ahora es el momento de pasar al Charting Spacey (si aún no se está ejecutando) enciende:",
"updated": 1629578564301
}
]
},
@@ -66,8 +76,13 @@
"text": "Nimm dir Zeit und erkunde die visuellen Ergebnisse. Wende den SMA-Indikator auf den Chart an und vergewissere dich, dass der Bot die Position zum erwarteten Zeitpunkt eingenommen hat.",
"updated": 1622980791002,
"style": "Success"
},
{
"language": "ES",
"text": "Tómese su tiempo y explore los resultados visuales. Aplique el indicador SMA al gráfico y asegúrese de que el bot haya tomado posición cuando se esperaba",
"updated": 1629578671372
}
]
}
]
}
}
@@ -15,6 +15,11 @@
"text": "Dies ist der letzte Schritt in diesem Tutorial, aber ein erster großer Schritt für dich!",
"updated": 1622980855701,
"style": "Definition"
},
{
"language": "ES",
"text": "Este es el paso final de este tutorial, ¡pero un primer gran paso para ti!",
"updated": 1629578693755
}
]
},
@@ -29,6 +34,11 @@
"text": "Nachdem du nun gesehen hast, wie schnell und einfach es ist, einfache Strategien in SA einzusetzen, lasse ich dich mit einigen Tipps zurück, die du erforschen kannst.",
"updated": 1622980866244,
"style": "Text"
},
{
"language": "ES",
"text": "Ahora que ha visto lo rápido y fácil que es implementar estrategias simples en SA, le dejo algunos consejos que puede explorar.",
"updated": 1629578879458
}
]
},
@@ -41,6 +51,11 @@
"text": "Vielleicht kannst du einen neuen Indikator hinzufügen und seine Eigenschaften wie einen zusätzlichen Filter für die Trigger Stage verwenden",
"updated": 1622981671905,
"style": "Text"
},
{
"language": "ES",
"text": "Tal vez puedas agregar un nuevo indicador y usar sus propiedades como un filtro adicional para el Trigger Stage.",
"updated": 1629578981875
}
],
"updated": 1622980962381
@@ -54,6 +69,11 @@
"text": "Oder du kannst den SL so modifizieren, dass er einen Trailing hat, anstatt fest zu sein.",
"updated": 1622980929319,
"style": "Text"
},
{
"language": "ES",
"text": "O puedes modificar el SL para tener uno final en lugar de ser fijo.",
"updated": 1629579019376
}
]
},
@@ -67,6 +87,11 @@
"text": "Vielen Dank für deine Zeit. Hier findest du einen ausführlicheren Artikel: http://bit.ly/9808usHelloWorld",
"updated": 1622980916321,
"style": "Note"
},
{
"language": "ES",
"text": "Gracias por tu tiempo. Puede leer un artículo más detallado aquí: http://bit.ly/9808usHelloWorld",
"updated": 1629579335349
}
]
}
@@ -7,29 +7,71 @@
"project": "Foundations",
"name": "Market/market"
},
"text": "This tutorial walks you through the process of setting up a new Market on which to run data mining and trading operations."
"text": "This tutorial walks you through the process of setting up a new Market on which to run data mining and trading operations.",
"translations": [
{
"language": "ES",
"text": "Este tutorial te guía a través del proceso de configuración de un nuevo mercado en el que ejecutar operaciones de minería de datos y comercio.",
"updated": 1628985038532
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Setting up a new Market involves:"
"text": "Setting up a new Market involves:",
"translations": [
{
"language": "ES",
"text": "Configurar un nuevo Market implica:",
"updated": 1628985109327
}
]
},
{
"style": "List",
"text": "1. Adding the assets for the exchange of choice."
"text": "1. Adding the assets for the exchange of choice.",
"translations": [
{
"language": "ES",
"text": "1. Añadiendo los assets para el exchange de elección.",
"updated": 1628985249427
}
]
},
{
"style": "List",
"text": "2. Setting up a market with the said assets."
"text": "2. Setting up a market with the said assets.",
"translations": [
{
"language": "ES",
"text": "2. Creación de un mercado con dichos assets.",
"updated": 1628990068651
}
]
},
{
"style": "List",
"text": "3. Installing the market "
"text": "3. Installing the market ",
"translations": [
{
"language": "ES",
"text": "3. Instalando el mercado",
"updated": 1628990055678
}
]
},
{
"style": "Callout",
"text": "When you click the Next button below, you will go to the Exchange Assets node under Binance, in the Crypto Ecosystem hierarchy. You may learn how to install a market in this exchange so that you may do the same in your exchange of choice later on.",
"updated": 1615202737286
"updated": 1615202737286,
"translations": [
{
"language": "ES",
"text": "Cuando hagas clic en el botón Next a continuación, irás al nodo Exchange Assets bajo Binance, en la jerarquía Crypto Ecosystem. Puedes aprender a instalar un mercado en este exchange para que puedas hacer lo mismo en tu exchange de elección más adelante.",
"updated": 1628991773444
}
]
}
]
}
@@ -4,20 +4,41 @@
"type": "Tutorial Topic - Add the Assets",
"definition": {
"icon": {
"project": "Foundations",
"name": "asset"
"name": "Market/asset",
"project": "Foundations"
},
"text": "If the assets you wish to work with are not listed under Exchange Assets, you must add and configure them first."
"text": "If the assets you wish to work with are not listed under Exchange Assets, you must add and configure them first.",
"translations": [
{
"language": "ES",
"text": "Si los activos con los que desea trabajar no se enumeran en Activos de Exchange, primero debe agregarlos y configurarlos.",
"updated": 1629162948016
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "In this section of the tutorial, you will learn to define which assets you wish to work with.",
"updated": 1617210801606
"updated": 1617210801606,
"translations": [
{
"language": "ES",
"text": "En esta sección del tutorial, aprenderás a definir con qué assets deseas trabajar.",
"updated": 1629162994984
}
]
},
{
"style": "Success",
"text": "Each exchange may list hundreds of assets, however, you will likely be interested in just a few. Some automated operations may feed on your definitions, so keeping them free of junk is always a good idea."
"text": "Each exchange may list hundreds of assets, however, you will likely be interested in just a few. Some automated operations may feed on your definitions, so keeping them free of junk is always a good idea.",
"translations": [
{
"language": "ES",
"text": "Cada exchange puede enumerar cientos de assets, sin embargo, es probable que solo te interesen unos pocos. Algunas operaciones automatizadas pueden alimentarse de tus definiciones, por lo que mantenerlas libres de basura es siempre una buena idea.",
"updated": 1629163406741
}
]
}
]
}
@@ -4,15 +4,29 @@
"type": "Tutorial Step - Add the Assets 1",
"definition": {
"icon": {
"project": "Foundations",
"name": "exchange-assets"
"name": "Exchange/exchange-assets",
"project": "Foundations"
},
"text": "Open the Exchange Assets node menu and use the Add Asset button to add the required assets."
"text": "Open the Exchange Assets node menu and use the Add Asset button to add the required assets.",
"translations": [
{
"language": "ES",
"text": "Abre el menú del nodo Exchange Assets y usa el botón Add Asset para agregar los requeridos assets.",
"updated": 1628992100719
}
]
},
"paragraphs": [
{
"style": "Important",
"text": "Assets under Exchange Assets may not be duplicated. If the definitions for the assets you are interested in already exist, you may reuse them instead of creating new ones. If such is the case, simply skip the next few steps until you need to set up the Market."
"text": "Assets under Exchange Assets may not be duplicated. If the definitions for the assets you are interested in already exist, you may reuse them instead of creating new ones. If such is the case, simply skip the next few steps until you need to set up the Market.",
"translations": [
{
"language": "ES",
"text": "Assets bajo Exchange Assets no se puede duplicar. Si las definiciones de la assets si te interesa que ya existan, puedes reutilizarlos en lugar de crear otros nuevos. Si ese es el caso, simplemente omite los siguientes pasos hasta que necesites configurar el Market.",
"updated": 1628992173230
}
]
}
]
}
@@ -4,11 +4,18 @@
"type": "Tutorial Step - Add the Assets 2",
"definition": {
"icon": {
"project": "Foundations",
"name": "asset"
"name": "Market/asset",
"project": "Foundations"
},
"text": "Edit the configuration of each of the new assets entering the ticker (as listed by the exchange) in the codeName property. ",
"updated": 1617210890633
"updated": 1617210890633,
"translations": [
{
"language": "ES",
"text": "Edita la configuración de cada uno de los nuevos activos que ingresan al ticker (según lo enumerado por el exchange) en la propiedad codeName.",
"updated": 1629163635069
}
]
},
"paragraphs": [
{
@@ -22,7 +29,14 @@
},
{
"style": "Note",
"text": "If the icon for the configured assets exist in the image library, the default icon is replaced automatically."
"text": "If the icon for the configured assets exist in the image library, the default icon is replaced automatically.",
"translations": [
{
"language": "ES",
"text": "Si el icono de los assets configurados existe en la biblioteca de imágenes, el icono predeterminado se reemplaza automáticamente.",
"updated": 1629163669241
}
]
}
]
}
@@ -4,19 +4,40 @@
"type": "Tutorial Step - Add the Assets 3",
"definition": {
"icon": {
"project": "Foundations",
"name": "asset"
"name": "Market/asset",
"project": "Foundations"
},
"text": "Label the assets with the descriptive name of the coin or token, for ease of use. For example: Ether."
"text": "Label the assets with the descriptive name of the coin or token, for ease of use. For example: Ether.",
"translations": [
{
"language": "ES",
"text": "Etiqueta los assets con el nombre descriptivo de la moneda o ficha, para facilitar su uso. Por ejemplo: Ether.",
"updated": 1629163866099
}
]
},
"paragraphs": [
{
"style": "List",
"text": "Step 3: Label Nodes"
"text": "Step 3: Label Nodes",
"translations": [
{
"language": "ES",
"text": "Step 3: Etiqueta lols nodos",
"updated": 1629163910016
}
]
},
{
"style": "Success",
"text": "Keeping a tidy Workspace with proper labels for significant nodes helps in managing large operations and administering complexity."
"text": "Keeping a tidy Workspace with proper labels for significant nodes helps in managing large operations and administering complexity.",
"translations": [
{
"language": "ES",
"text": "Mantener un espacio de trabajo ordenado con etiquetas adecuadas para nodos importantes ayuda a gestionar grandes operaciones y a administrar la complejidad.",
"updated": 1629163971957
}
]
}
]
}
@@ -4,20 +4,41 @@
"type": "Tutorial Topic - Set Up the Market",
"definition": {
"icon": {
"project": "Foundations",
"name": "market"
"name": "Market/market",
"project": "Foundations"
},
"text": "If there is no Market set up with the pair you wish to work with under Exchange Markets, you must set up the market definition before installing it."
"text": "If there is no Market set up with the pair you wish to work with under Exchange Markets, you must set up the market definition before installing it.",
"translations": [
{
"language": "ES",
"text": "Si no hay un Market configurado con el par con el que deseas trabajar en Exchange Markets, debes configurar la definición de mercado antes de instalarlo.",
"updated": 1629164083032
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "The next few steps teach you how to set up the market so that you may later install it."
"text": "The next few steps teach you how to set up the market so that you may later install it.",
"translations": [
{
"language": "ES",
"text": "Los siguientes pasos te enseñarán cómo configurar el mercado para que puedas instalarlo más tarde.",
"updated": 1629164109911
}
]
},
{
"style": "Important",
"text": "Make sure that the combination of Market Base Asset and Market Quoted Asset that you wish to define as a Market in Superalgos exists as a market listed at the exchange.",
"updated": 1617211041220
"updated": 1617211041220,
"translations": [
{
"language": "ES",
"text": "Asegúrese de que la combinación de Market Base Asset y Market Quoted Asset que desea definir como Market en Superalgos existe como un mercado que cotiza en el exchange.",
"updated": 1629164457557
}
]
}
]
}
@@ -4,20 +4,41 @@
"type": "Tutorial Step - Set Up the Market 1",
"definition": {
"icon": {
"project": "Foundations",
"name": "market"
"name": "Market/market",
"project": "Foundations"
},
"text": "Add a new Market node using the Add Market option on the menu."
"text": "Add a new Market node using the Add Market option on the menu.",
"translations": [
{
"language": "ES",
"text": "Añade un nuevo nodo Market usando el Add Market opción en el menú.",
"updated": 1629164947647
}
]
},
"paragraphs": [
{
"style": "Success",
"text": "A Market node should be added featuring two offspring: a Market Base Asset and a Market Quoted Asset.",
"updated": 1617211390857
"updated": 1617211390857,
"translations": [
{
"language": "ES",
"text": "Se debe agregar un nodo de Market con dos descendientes: a Market Base Asset y a Market Quoted Asset.",
"updated": 1629165004233
}
]
},
{
"style": "Important",
"text": "Before continuing, make sure which is the base and which the quoted asset in the exchange's listing. Usually, the base asset is the first in the name of the pair, but this is not enforced on every exchange, so be vigilant."
"text": "Before continuing, make sure which is the base and which the quoted asset in the exchange's listing. Usually, the base asset is the first in the name of the pair, but this is not enforced on every exchange, so be vigilant.",
"translations": [
{
"language": "ES",
"text": "Antes de continuar, asegúrate de cuál es la base y cuál es el asset cotizado en la cotización de el exchange. Por lo general, el asset base es el primero en el nombre del par, pero esto no se aplica en todos los exchanges, así que esté atento.",
"updated": 1629165598676
}
]
}
]
}
@@ -4,15 +4,29 @@
"type": "Tutorial Step - Set Up the Market 2",
"definition": {
"icon": {
"project": "Foundations",
"name": "asset"
"name": "Market/asset",
"project": "Foundations"
},
"text": "Establish a reference from the Market Base Asset node in the Market you just defined to the corresponding Asset node defined under Exchange Assets."
"text": "Establish a reference from the Market Base Asset node in the Market you just defined to the corresponding Asset node defined under Exchange Assets.",
"translations": [
{
"language": "ES",
"text": "Establecer una referencia de el nodo Market Base Asset en el Market que acabas de definir a el correspondiente nodo Asset definido bajo Exchange Assets.",
"updated": 1629165785229
}
]
},
"paragraphs": [
{
"style": "Note",
"text": "If you are not familiar with establishing references, please read about the topic in the documentation."
"text": "If you are not familiar with establishing references, please read about the topic in the documentation.",
"translations": [
{
"language": "ES",
"text": "Si no estás familiarizado con el establecimiento de referencias, lee sobre el tema en la documentación.",
"updated": 1629165919563
}
]
}
]
}
@@ -4,16 +4,30 @@
"type": "Tutorial Step - Set Up the Market 3",
"definition": {
"icon": {
"project": "Foundations",
"name": "asset"
"name": "Market/asset",
"project": "Foundations"
},
"text": "Now establish a reference from the Market Quoted Asset node in the Market you just defined to the corresponding Asset node defined under Exchange Assets."
"text": "Now establish a reference from the Market Quoted Asset node in the Market you just defined to the corresponding Asset node defined under Exchange Assets.",
"translations": [
{
"language": "ES",
"text": "Ahora establece una referencia del nodo Market Quoted Asset en el Market que acaba de definir a la correspondiente nodo Asset definido bajo Exchange Assets.",
"updated": 1629166070472
}
]
},
"paragraphs": [
{
"style": "Success",
"text": "You are almost done with this references!",
"updated": 1617212021559
"updated": 1617212021559,
"translations": [
{
"language": "ES",
"text": "¡Ya casi has terminado con estas referencias!",
"updated": 1629166084110
}
]
}
]
}
@@ -4,21 +4,42 @@
"type": "Tutorial Step - Set Up the Market 4",
"definition": {
"icon": {
"project": "Foundations",
"name": "market"
"name": "Market/market",
"project": "Foundations"
},
"text": "Label the Market with the ticker names corresponding to the Market Base Asset and the Market Quoted Asset, just like the exchange listing. ",
"updated": 1617212204904
"updated": 1617212204904,
"translations": [
{
"language": "ES",
"text": "Etiqueta el Market con los nombres de ticker correspondientes a el Market Base Asset ay el Market Quoted Asset, al igual que la lista de exchange.",
"updated": 1629247010585
}
]
},
"paragraphs": [
{
"style": "Note",
"text": "For example: ETH/USDT.",
"updated": 1617212210997
"updated": 1617212210997,
"translations": [
{
"language": "ES",
"text": "Por ejemplo: ETH/USDT.",
"updated": 1629247028876
}
]
},
{
"style": "Success",
"text": "Keeping a tidy Workspace with proper labels for significant nodes helps in managing large operations and administering complexity. These labels may be used by other nodes!"
"text": "Keeping a tidy Workspace with proper labels for significant nodes helps in managing large operations and administering complexity. These labels may be used by other nodes!",
"translations": [
{
"language": "ES",
"text": "Manteniendo un ordenado Workspace con etiquetas adecuadas para nodos importantes, ayuda a gestionar grandes operaciones y a administrar la complejidad. ¡Estas etiquetas pueden ser utilizadas por otros nodos!",
"updated": 1629247073143
}
]
}
]
}
@@ -4,21 +4,42 @@
"type": "Tutorial Topic - Install the Market",
"definition": {
"icon": {
"project": "Foundations",
"name": "market"
"name": "Market/market",
"project": "Foundations"
},
"text": "You finished the setup required to install the market! The rest is fully automated!",
"updated": 1617212322242
"updated": 1617212322242,
"translations": [
{
"language": "ES",
"text": "¡Terminaste la configuración requerida para instalar el mercado! ¡El resto está completamente automatizado!",
"updated": 1629247436746
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "Click the Install Market button on the Market node you just finished setting up. Now that the Market is set up, installing it is just a click away.",
"updated": 1617212281868
"updated": 1617212281868,
"translations": [
{
"language": "ES",
"text": "Haz clic en el botón Install Market en el nodo Market que acabas de terminar de configurar. Ahora que el Market está configurado, instalarlo está a solo un clic de distancia.",
"updated": 1629247557848
}
]
},
{
"style": "Note",
"text": "The Install Market function sets up many data structures in the local Network Node and in the Charting Space. The next few steps in the tutorial will help you get familiar with the installation."
"text": "The Install Market function sets up many data structures in the local Network Node and in the Charting Space. The next few steps in the tutorial will help you get familiar with the installation.",
"translations": [
{
"language": "ES",
"text": "La Install Market La función configura muchas estructuras de datos en el local Network Node y en el Charting Space. Los siguientes pasos del tutorial te ayudarán a familiarizarse con la instalación.",
"updated": 1629247622619
}
]
}
]
}
@@ -7,16 +7,37 @@
"project": "Foundations",
"name": "network-node"
},
"text": "The Install Market function sets up many data structures in the local Network Node."
"text": "The Install Market function sets up many data structures in the local Network Node.",
"translations": [
{
"language": "ES",
"text": "La instalación de la función Market configura muchas estructuras de datos en el local Network Node.",
"updated": 1629247715120
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "In the next few steps, you will verify that each of the expected data structures was created successfully. The expected structures are:"
"text": "In the next few steps, you will verify that each of the expected data structures was created successfully. The expected structures are:",
"translations": [
{
"language": "ES",
"text": "En los siguientes pasos, verificarás que cada una de las estructuras de datos esperadas se haya creado correctamente. Las estructuras esperadas son:",
"updated": 1629247883351
}
]
},
{
"style": "Callout",
"text": "1. Data Tasks tasks for all data mines included in your workspace.<br/><br/>2. Backtesting and live trading tasks for all included trading systems.<br/><br/>3. The corresponding Data Storage definitions."
"text": "1. Data Tasks tasks for all data mines included in your workspace.<br/><br/>2. Backtesting and live trading tasks for all included trading systems.<br/><br/>3. The corresponding Data Storage definitions.",
"translations": [
{
"language": "ES",
"text": "1. Data Tasks tareas para todas las minas de datos incluidas en tu espacio de trabajo.2. Backtesting and live trading tasks for all included trading systems.3. The corresponding Data Storage definitions.",
"updated": 1629247909377
}
]
}
]
}
@@ -4,27 +4,62 @@
"type": "Tutorial Step - Network Verification 1",
"definition": {
"icon": {
"project": "Foundations",
"name": "data-tasks"
"name": "Data/data-tasks",
"project": "Foundations"
},
"text": "Verify that the Data Tasks tasks for the corresponding Market were created successfully."
"text": "Verify that the Data Tasks tasks for the corresponding Market were created successfully.",
"translations": [
{
"language": "ES",
"text": "Verifica que las tareas del Data Tasks para el correspondiente Market fueron creadas con éxito.",
"updated": 1629248555223
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Look for the following data structures:"
"text": "Look for the following data structures:",
"translations": [
{
"language": "ES",
"text": "Busca las siguientes estructuras de datos:",
"updated": 1629248659569
}
]
},
{
"style": "List",
"text": "A Market Data Tasks node for the new market."
"text": "A Market Data Tasks node for the new market.",
"translations": [
{
"language": "ES",
"text": "Un nodo Market Data Tasks para el nuevo mercado.",
"updated": 1629248644175
}
]
},
{
"style": "List",
"text": "One Data Mine Tasks node for each Data Mine included in the Workspace."
"text": "One Data Mine Tasks node for each Data Mine included in the Workspace.",
"translations": [
{
"language": "ES",
"text": "Un nodo Data Mine Taskspor cada Data Mine incluido en el Workspace.",
"updated": 1629248688491
}
]
},
{
"style": "List",
"text": "One Task Manager per Data Mine and one Task for each bot defined in each data mine."
"text": "One Task Manager per Data Mine and one Task for each bot defined in each data mine.",
"translations": [
{
"language": "ES",
"text": "Un Task Manager por Data Mine y un Task para cada bot definido en cada mina de datos.",
"updated": 1629248744863
}
]
}
]
}
@@ -7,24 +7,59 @@
"project": "Foundations",
"name": "testing-trading-tasks"
},
"text": "Verify that the Testing Trading Tasks tasks for the corresponding Market were created successfully."
"text": "Verify that the Testing Trading Tasks tasks for the corresponding Market were created successfully.",
"translations": [
{
"language": "ES",
"text": "Verifica que las tareas del Testing Trading Tasks del correspondiente Market fueron creados con éxito.",
"updated": 1629248966784
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Look for the following data structures:"
"text": "Look for the following data structures:",
"translations": [
{
"language": "ES",
"text": "Busca las siguientes estructuras de datos:",
"updated": 1629249005363
}
]
},
{
"style": "List",
"text": "A Market Trading Tasks node for the new market."
"text": "A Market Trading Tasks node for the new market.",
"translations": [
{
"language": "ES",
"text": "Un nodo Market Trading Tasks para el nuevo mercado.",
"updated": 1629249052629
}
]
},
{
"style": "List",
"text": "One Trading Mine Tasks node for each trading mine included in the Workspace."
"text": "One Trading Mine Tasks node for each trading mine included in the Workspace.",
"translations": [
{
"language": "ES",
"text": "Un Trading Mine Tasks nodo para cada mina comercial incluida en el Workspace.",
"updated": 1629249077978
}
]
},
{
"style": "List",
"text": "One Task Manager per trading mine and one Task with a Backtesting Session for each Trading System in the workspace."
"text": "One Task Manager per trading mine and one Task with a Backtesting Session for each Trading System in the workspace.",
"translations": [
{
"language": "ES",
"text": "Un Task Manager por mina comercial y un Task con un Backtesting Session para cada Trading System en el espacio de trabajo.",
"updated": 1629249127594
}
]
}
]
}
@@ -7,16 +7,37 @@
"project": "Foundations",
"name": "production-trading-tasks"
},
"text": "Verify that the Production Trading Tasks tasks for the corresponding Market were created successfully."
"text": "Verify that the Production Trading Tasks tasks for the corresponding Market were created successfully.",
"translations": [
{
"language": "ES",
"text": "Verifica que las tareas Production Trading Tasks se crearon con éxito para el Market correspondiente.",
"updated": 1629249520590
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Look for the following data structures:"
"text": "Look for the following data structures:",
"translations": [
{
"language": "ES",
"text": "Busca las siguientes estructuras de datos:",
"updated": 1629249556254
}
]
},
{
"style": "List",
"text": "A Market Trading Tasks node for the new market."
"text": "A Market Trading Tasks node for the new market.",
"translations": [
{
"language": "ES",
"text": "Un Market Trading Tasks nodo para el nuevo mercado.",
"updated": 1629249638874
}
]
},
{
"style": "List",
@@ -24,7 +45,14 @@
},
{
"style": "List",
"text": "One Task Manager per Trading Mine and one Task with a Backtesting Session for each Trading System in the workspace."
"text": "One Task Manager per Trading Mine and one Task with a Backtesting Session for each Trading System in the workspace.",
"translations": [
{
"language": "ES",
"text": "Un Task Manager por Trading Mine y un Task con una Backtesting Session para cada Trading System en el espacio de trabajo.",
"updated": 1629249792961
}
]
}
]
}
@@ -4,23 +4,51 @@
"type": "Tutorial Step - Network Verification 4",
"definition": {
"icon": {
"project": "Foundations",
"name": "data-storage"
"name": "Data/data-storage",
"project": "Foundations"
},
"text": "Verify that the Data Storage nodes for the corresponding Market were created successfully."
"text": "Verify that the Data Storage nodes for the corresponding Market were created successfully.",
"translations": [
{
"language": "ES",
"text": "Verifica que los nodo Data Storage para el Market correspondiente se crearon con éxito.",
"updated": 1629249917009
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Look for the following data structures:"
"text": "Look for the following data structures:",
"translations": [
{
"language": "ES",
"text": "Busque las siguientes estructuras de datos:",
"updated": 1629249952621
}
]
},
{
"style": "List",
"text": "A Market Data Products node under Data Mines Data, with a Data Mine Products node for each Data Mine in the workspace."
"text": "A Market Data Products node under Data Mines Data, with a Data Mine Products node for each Data Mine in the workspace.",
"translations": [
{
"language": "ES",
"text": "Un nodo Market Data Products bajo Data Mines Data, con un nodo Data Mine Products para cada Data Mine en el espacio de trabajo.",
"updated": 1629250030704
}
]
},
{
"style": "List",
"text": "A Market Trading Products node under Trading Mines Data, with a Trading Session Reference for each trading session in the testing and production environments."
"text": "A Market Trading Products node under Trading Mines Data, with a Trading Session Reference for each trading session in the testing and production environments.",
"translations": [
{
"language": "ES",
"text": "Un nodo Market Trading Products bajo Trading Mines Data, con un Trading Session Reference para cada sesión de trading en los entornos de prueba y producción.",
"updated": 1629250105046
}
]
}
]
}
@@ -4,23 +4,51 @@
"type": "Tutorial Topic - Charts Verification",
"definition": {
"icon": {
"project": "Foundations",
"name": "charting-space"
"name": "Charting-Space/charting-space",
"project": "Foundations"
},
"text": "Beyond the data structures set up in the Network hierarchy, the Install Market function also sets up charts matching the trading sessions created."
"text": "Beyond the data structures set up in the Network hierarchy, the Install Market function also sets up charts matching the trading sessions created.",
"translations": [
{
"language": "ES",
"text": "Más allá de las estructuras de datos configuradas en la jerarquía de la Network, la función Install Market también configura gráficos que coinciden las sesiones de trading creadas.",
"updated": 1629250291168
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "In the next few steps you will verify that the expected data structures were created successfully."
"text": "In the next few steps you will verify that the expected data structures were created successfully.",
"translations": [
{
"language": "ES",
"text": "En los siguientes pasos, verificará que las estructuras de datos esperadas se hayan creado correctamente.",
"updated": 1629250307906
}
]
},
{
"style": "Callout",
"text": "The charts created allow working with each of the trading sessions independently."
"text": "The charts created allow working with each of the trading sessions independently.",
"translations": [
{
"language": "ES",
"text": "Los gráficos creados permiten trabajar con las Trading Session de forma independiente.",
"updated": 1629250720714
}
]
},
{
"style": "Success",
"text": "Notice from the organization of the charts that Superalgos allows scaling up your operation to unlimited trading systems and charts."
"text": "Notice from the organization of the charts that Superalgos allows scaling up your operation to unlimited trading systems and charts.",
"translations": [
{
"language": "ES",
"text": "Observa desde la organización de los gráficos que Superalgos permite escalar tu operación a gráficos y sistemas comerciales ilimitados.",
"updated": 1629250466323
}
]
}
]
}
@@ -4,23 +4,51 @@
"type": "Tutorial Step - Charts Verification 1",
"definition": {
"icon": {
"project": "Foundations",
"name": "charting-space"
"name": "Charting-Space/charting-space",
"project": "Foundations"
},
"text": "Verify that the Charting Space data structures for the corresponding Market were created successfully."
"text": "Verify that the Charting Space data structures for the corresponding Market were created successfully.",
"translations": [
{
"language": "ES",
"text": "Verifica que las estructuras de datos del Charting Space para el mercado correspondiente se crearon con éxito.",
"updated": 1629251098125
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Look for the following data structures:"
"text": "Look for the following data structures:",
"translations": [
{
"language": "ES",
"text": "Busca las siguientes estructuras de datos:",
"updated": 1629251126491
}
]
},
{
"style": "List",
"text": "A Time Machine node for each trading session created in the Testing Trading Tasks."
"text": "A Time Machine node for each trading session created in the Testing Trading Tasks.",
"translations": [
{
"language": "ES",
"text": "Un nodo Time Machine para cada Trading Session creada en el Testing Trading Tasks.",
"updated": 1629251359090
}
]
},
{
"style": "List",
"text": "A Time Machine node for each trading session created in the Production Trading Tasks."
"text": "A Time Machine node for each trading session created in the Production Trading Tasks.",
"translations": [
{
"language": "ES",
"text": "Un nodo Time Machine oara cada Trading Session creada en el Production Trading Tasks.",
"updated": 1629251407209
}
]
}
]
}
@@ -4,23 +4,51 @@
"type": "Tutorial Step - Charts Verification 2",
"definition": {
"icon": {
"project": "Foundations",
"name": "time-machine"
"name": "Time/time-machine",
"project": "Foundations"
},
"text": "Verify that the time machines created show up on the charting space... you should find..."
"text": "Verify that the time machines created show up on the charting space... you should find...",
"translations": [
{
"language": "ES",
"text": "Verifica que las máquinas del tiempo creadas aparezcan en el espacio de gráficos ... deberías encontrar ...",
"updated": 1629251601715
}
]
},
"paragraphs": [
{
"style": "List",
"text": "A Time Machine for each trading session created in the Testing Trading Tasks."
"text": "A Time Machine for each trading session created in the Testing Trading Tasks.",
"translations": [
{
"language": "ES",
"text": "Un Time Machine para cada Trading Session crada en el Testing Trading Tasks.",
"updated": 1629251649077
}
]
},
{
"style": "List",
"text": "A Time Machine for each trading session created in the Production Trading Tasks."
"text": "A Time Machine for each trading session created in the Production Trading Tasks.",
"translations": [
{
"language": "ES",
"text": "Un Time Machine para cada Trading Session creado en el Production Trading Tasks.",
"updated": 1629251693396
}
]
},
{
"style": "Success",
"text": "Hover your mouse over a chart to see what Crypto Exchange and Market it features."
"text": "Hover your mouse over a chart to see what Crypto Exchange and Market it features.",
"translations": [
{
"language": "ES",
"text": "Pasa el mouse sobre un gráfico para ver qué Crypto Exchange y Market contiene.",
"updated": 1629251750388
}
]
}
]
}
@@ -4,15 +4,29 @@
"type": "Tutorial Topic - You Made It!",
"definition": {
"icon": {
"project": "Foundations",
"name": "tutorial"
"name": "Tutorial/tutorial",
"project": "Foundations"
},
"text": "Congratulations... you have reached the end of this tutorial!"
"text": "Congratulations... you have reached the end of this tutorial!",
"translations": [
{
"language": "ES",
"text": "Felicitaciones ... ¡has llegado al final de este tutorial!",
"updated": 1629251820232
}
]
},
"paragraphs": [
{
"style": "Success",
"text": "You may revisit this tutorial at any point. If you select the Play option on the menu, you start right from the beginning. If you select the Resume option instead, you start where you last left, or where you last skipped a step."
"text": "You may revisit this tutorial at any point. If you select the Play option on the menu, you start right from the beginning. If you select the Resume option instead, you start where you last left, or where you last skipped a step.",
"translations": [
{
"language": "ES",
"text": "Puedes volver a visitar este tutorial en cualquier momento. Si seleccionas el Play en el menú, comienza desde el principio. Si seleccionas el Resume en su lugar, comienzas donde lo dejaste por última vez o donde saltaste un paso por última vez.",
"updated": 1629251900929
}
]
}
]
}
@@ -4,19 +4,40 @@
"type": "Tutorial - Intro to Trading Systems",
"definition": {
"icon": {
"project": "Foundations",
"name": "trading-system"
"name": "Trading\\trading-system",
"project": "Foundations"
},
"text": "Trading systems are the heart and soul of systematic trading, as they concentrate the biggest chunk of trading intelligence."
"text": "Trading systems are the heart and soul of systematic trading, as they concentrate the biggest chunk of trading intelligence.",
"translations": [
{
"language": "ES",
"text": "Los sistemas de trading son el corazón y el alma del trading sistemático, ya que concentran la mayor parte de la inteligencia trading.",
"updated": 1629587307428
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "The rest of the infrastructure built into Superalgos&mdash;data mining and visualization, the trading bot and trading engine, the visual strategy designer and debugger&mdash;all have significant equity in the intelligence pie, but it's fair to argue that was developed to support the design, testing, and deployment of trading systems!"
"text": "The rest of the infrastructure built into Superalgos&mdash;data mining and visualization, the trading bot and trading engine, the visual strategy designer and debugger&mdash;all have significant equity in the intelligence pie, but it's fair to argue that was developed to support the design, testing, and deployment of trading systems!",
"translations": [
{
"language": "ES",
"text": "El resto de la infraestructura integrada en Superalgos: minería y visualización de datos, el trading bot y trading engine, el diseñador de estrategia visual y el depurador, todos tienen una participación significativa en el pastel de inteligencia, pero es justo argumentar que fue desarrollado para respaldar el diseño, las pruebas y la implementación de sistemas de trading.",
"updated": 1629587395422
}
]
},
{
"style": "Callout",
"text": "This first tutorial explains how Superalgos views and handles a Trading System. The rest of the tutorials in the series teach you how to build them!"
"text": "This first tutorial explains how Superalgos views and handles a Trading System. The rest of the tutorials in the series teach you how to build them!",
"translations": [
{
"language": "ES",
"text": "Este primer tutorial explica cómo Superalgos ve y maneja un Trading System. ¡El resto de los tutoriales de la serie te enseñan cómo construirlos!",
"updated": 1629587450801
}
]
}
]
}
@@ -4,24 +4,52 @@
"type": "Tutorial Topic - Frame It Flexibly!",
"definition": {
"icon": {
"project": "Foundations",
"name": "trading-system"
"name": "Trading\\trading-system",
"project": "Foundations"
},
"text": "A Trading System governs trading strategies, and provides a flexible&mdash;but structured&mdash; framework to build them."
"text": "A Trading System governs trading strategies, and provides a flexible&mdash;but structured&mdash; framework to build them.",
"translations": [
{
"language": "ES",
"text": "Un Trading System rige las estrategias trading proporciona un marco flexible, pero estructurado, para desarrollarlas.",
"updated": 1629587546135
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "Please, read this page to get up to speed with how trading systems work!",
"updated": 1610367185240
"updated": 1610367185240,
"translations": [
{
"language": "ES",
"text": "Por favor, lea esta página para ponerse al día con el funcionamiento de los sistemas comerciales.",
"updated": 1629587573430
}
]
},
{
"style": "Success",
"text": "There is no substitute for knowledge, so you will need to do some reading before I get your hands dirty with good ol' trading logic!"
"text": "There is no substitute for knowledge, so you will need to do some reading before I get your hands dirty with good ol' trading logic!",
"translations": [
{
"language": "ES",
"text": "¡No hay sustituto para el conocimiento, por lo que tendrás que leer un poco antes de que me ensucie las manos con la buena lógica del trading!",
"updated": 1629587618899
}
]
},
{
"style": "Warning",
"text": "Skipping the reading may result in permanent neurological impairment. Your call!"
"text": "Skipping the reading may result in permanent neurological impairment. Your call!",
"translations": [
{
"language": "ES",
"text": "Saltarse la lectura puede resultar en un deterioro neurológico permanente. ¡Tu llamada!",
"updated": 1629587887766
}
]
}
]
}
@@ -4,31 +4,73 @@
"type": "Tutorial Step - Points to Take Home...",
"definition": {
"icon": {
"project": "Foundations",
"name": "trading-system"
"name": "Trading\\trading-system",
"project": "Foundations"
},
"text": "There are some key learnings in the previous reading: multiple strategies, single positions, and precedence."
"text": "There are some key learnings in the previous reading: multiple strategies, single positions, and precedence.",
"translations": [
{
"language": "ES",
"text": "Hay algunos aprendizajes clave en la lectura anterior: estrategias múltiples, posiciones únicas y precedencia.",
"updated": 1629588118888
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Let's take some mental notes for what comes next:"
"text": "Let's take some mental notes for what comes next:",
"translations": [
{
"language": "ES",
"text": "Tomemos algunas notas mentales para lo que viene a continuación:",
"updated": 1629588135560
}
]
},
{
"style": "List",
"text": "Multiple strategies may coexist within a trading system&mdash;as many as you wish."
"text": "Multiple strategies may coexist within a trading system&mdash;as many as you wish.",
"translations": [
{
"language": "ES",
"text": "Pueden coexistir múltiples estrategias dentro de un sistema trading, tantas como desees.",
"updated": 1629588192365
}
]
},
{
"style": "List",
"text": "One active strategy with one open position at any given moment is allowed only."
"text": "One active strategy with one open position at any given moment is allowed only.",
"translations": [
{
"language": "ES",
"text": "Solo se permite una estrategia activa con una posición abierta en un momento dado.",
"updated": 1629588175743
}
]
},
{
"style": "List",
"text": "Precedence is given by the order in which strategies are defined around the Trading System node. You may change the order, of course!"
"text": "Precedence is given by the order in which strategies are defined around the Trading System node. You may change the order, of course!",
"translations": [
{
"language": "ES",
"text": "La precedencia viene dada por el orden en el que se definen las estrategias alrededor del nodo Trading System. ¡Puedes cambiar el orden!",
"updated": 1629588262008
}
]
},
{
"style": "Note",
"text": "You are probably asking why? Do these rules sound arbitrary? They are, for good reason!"
"text": "You are probably asking why? Do these rules sound arbitrary? They are, for good reason!",
"translations": [
{
"language": "ES",
"text": "Probablemente te estés preguntando.. ¿por qué estas reglas suenan arbitrarias? ¡Lo son!",
"updated": 1629588865354
}
]
}
]
}
@@ -4,23 +4,51 @@
"type": "Tutorial Step - But... But... Why?",
"definition": {
"icon": {
"project": "Foundations",
"name": "trading-system"
"name": "Trading\\trading-system",
"project": "Foundations"
},
"text": "Why would I want to have multiple strategies within a trading system, when only one of them may trade at any point?"
"text": "Why would I want to have multiple strategies within a trading system, when only one of them may trade at any point?",
"translations": [
{
"language": "ES",
"text": "¿Por qué querría tener múltiples estrategias dentro de un Trading System, cuando solo una de ellas puede operar en cualquier momento?",
"updated": 1629591838961
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Before answering the burning question, let's take a look at a couple of examples. Take a look at the two strategies within the Weak-hands Buster (WHB v2) trading system!"
"text": "Before answering the burning question, let's take a look at a couple of examples. Take a look at the two strategies within the Weak-hands Buster (WHB v2) trading system!",
"translations": [
{
"language": "ES",
"text": "Antes de responder a la pregunta candente, echemos un vistazo a un par de ejemplos. ¡Echa un vistazo a las dos estrategias dentro del Tradiing System Weak-Hands Buster (WHB v2)!",
"updated": 1629598150880
}
]
},
{
"style": "Callout",
"text": "Explore the definitions of the Trigger On Event on the Trigger Stage and see if you notice the difference between the two."
"text": "Explore the definitions of the Trigger On Event on the Trigger Stage and see if you notice the difference between the two.",
"translations": [
{
"language": "ES",
"text": "Explore las definiciones de Trigger On Event sobre el Trigger Stagey vea si nota la diferencia entre los dos.",
"updated": 1629598211253
}
]
},
{
"style": "Success",
"text": "There's a hint in the name of each strategy!"
"text": "There's a hint in the name of each strategy!",
"translations": [
{
"language": "ES",
"text": "¡Hay una pista en el nombre de cada estrategia!",
"updated": 1629598225693
}
]
}
]
}
@@ -7,16 +7,37 @@
"project": "Foundations",
"name": "condition"
},
"text": "Did you find the difference? Don't worry if you didn't! There are lots of conditions! I'll give you another hint!"
"text": "Did you find the difference? Don't worry if you didn't! There are lots of conditions! I'll give you another hint!",
"translations": [
{
"language": "ES",
"text": "¿Encontraste la diferencia? ¡No te preocupe si no lo hiciste! ¡Hay muchas condiciones! ¡Te daré otra pista!",
"updated": 1629589533343
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "Look again and notice that the first seven conditions of the Trigger On Event are the same on both strategies! The remaining conditions are different, though!"
"text": "Look again and notice that the first seven conditions of the Trigger On Event are the same on both strategies! The remaining conditions are different, though!",
"translations": [
{
"language": "ES",
"text": "Mira de nuevo y observa que las primeras siete condiciones del Trigger On Event son iguales en ambas estrategias! ¡Sin embargo, las condiciones restantes son diferentes!",
"updated": 1629589848429
}
]
},
{
"style": "Success",
"text": "You may drag the Trigger On Event of a strategy and pin it closer to the event of the other strategy for easier comparison!"
"text": "You may drag the Trigger On Event of a strategy and pin it closer to the event of the other strategy for easier comparison!",
"translations": [
{
"language": "ES",
"text": "Puedes arrastrar el Trigger On Event de una estrategia y fíjela más cerca del evento de la otra estrategia para facilitar la comparación.",
"updated": 1629589881277
}
]
}
]
}
@@ -4,19 +4,40 @@
"type": "Tutorial Step - A Particular Case...",
"definition": {
"icon": {
"project": "Foundations",
"name": "trading-strategy"
"name": "Trading\\trading-strategy",
"project": "Foundations"
},
"text": "Both strategies are virtually the same in that they share the same base rules for triggering... with minor differences..."
"text": "Both strategies are virtually the same in that they share the same base rules for triggering... with minor differences...",
"translations": [
{
"language": "ES",
"text": "Ambas estrategias son prácticamente iguales en el sentido de que comparten las mismas reglas básicas para la activación... ",
"updated": 1629590239242
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "Beyond the seven conditions in common, the Steep strategy has one additional Condition while the Xtreme strategy has three. We won't analyze those differences one by one, although you may if you wish! Let's instead reveal the underlying concept behind the differences:"
"text": "Beyond the seven conditions in common, the Steep strategy has one additional Condition while the Xtreme strategy has three. We won't analyze those differences one by one, although you may if you wish! Let's instead reveal the underlying concept behind the differences:",
"translations": [
{
"language": "ES",
"text": "Más allá de las siete condiciones en común, la Steep strategy tiene un Condition adicional mientras que la estrategia Xtreme tiene tres. No analizaremos esas diferencias una a una, ¡aunque puede hacerlo si lo desea! En su lugar, revelemos el concepto subyacente detrás de las diferencias:",
"updated": 1629590038879
}
]
},
{
"style": "Callout",
"text": "Within the market Situation defined by the first seven conditions, the Steep strategy deals with a certain type of price action&mdash;price falling on a steep curve&mdash;while the Xtreme strategy deals with price falling on an extremely steep curve!"
"text": "Within the market Situation defined by the first seven conditions, the Steep strategy deals with a certain type of price action&mdash;price falling on a steep curve&mdash;while the Xtreme strategy deals with price falling on an extremely steep curve!",
"translations": [
{
"language": "ES",
"text": "Dentro de la situación de mercado definida por las primeras siete condiciones, la estrategia Steep se ocupa de un cierto tipo de acción del precio, el precio que cae en una curva pronunciada, mientras que la estrategia Xtreme se ocupa de la caída del precio en una curva extremadamente pronunciada.",
"updated": 1629590224948
}
]
}
]
}
@@ -4,19 +4,40 @@
"type": "Tutorial Step - Another Example?",
"definition": {
"icon": {
"project": "Foundations",
"name": "trading-system"
"name": "Trading\\trading-system",
"project": "Foundations"
},
"text": "Let's take a look at another example! This is BB Top Bounce, a Trading System based on the bounce off the upper Bollinger Band trading idea."
"text": "Let's take a look at another example! This is BB Top Bounce, a Trading System based on the bounce off the upper Bollinger Band trading idea.",
"translations": [
{
"language": "ES",
"text": "¡Echemos un vistazo a otro ejemplo! Este es BB Top Bounce, un Trading System basado en el rebote de la parte superior de la idea de trading Bollinger Band.",
"updated": 1629590642973
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "Expand the trading system node... Let's see what it may teach us!"
"text": "Expand the trading system node... Let's see what it may teach us!",
"translations": [
{
"language": "ES",
"text": "Expande el nodo del Trading System ... ¡Veamos qué nos puede enseñar!",
"updated": 1629590784815
}
]
},
{
"style": "Note",
"text": "I told you! You may have as many strategies as you wish under the same trading system! Well... there your are!"
"text": "I told you! You may have as many strategies as you wish under the same trading system! Well... there your are!",
"translations": [
{
"language": "ES",
"text": "¡Te dije! ¡Puedes tener tantas estrategias como desees bajo el mismo Trading System! Bueno ... ¡ahí estás!",
"updated": 1629590821468
}
]
}
]
}
@@ -7,21 +7,49 @@
"project": "Foundations",
"name": "condition"
},
"text": "BB Top Bounce features an interesting approach: it defines the trading idea with three simple conditions."
"text": "BB Top Bounce features an interesting approach: it defines the trading idea with three simple conditions.",
"translations": [
{
"language": "ES",
"text": "BB Top Bounce presenta un enfoque interesante: define la idea comercial con tres condiciones simples.",
"updated": 1629591593112
}
]
},
"paragraphs": [
{
"style": "Text",
"text": "You are looking at the Trigger On Event of the first strategy. Notice the first three conditions defined..."
"text": "You are looking at the Trigger On Event of the first strategy. Notice the first three conditions defined...",
"translations": [
{
"language": "ES",
"text": "Estás mirando el Trigger On Event de la primera estrategia. Observa las tres primeras condiciones definidas...",
"updated": 1629591638723
}
]
},
{
"style": "Callout",
"text": "Now go and look at the trigger on event of any of the other strategies... What do you see?"
"text": "Now go and look at the trigger on event of any of the other strategies... What do you see?",
"translations": [
{
"language": "ES",
"text": "Ahora ve y mira el desencadenante de cualquiera de las otras estrategias ... ¿Qué ves?",
"updated": 1629591679346
}
]
},
{
"style": "Text",
"text": "Exactly! All strategies feature the same first three conditions on the trigger on event. This shows that all strategies are based on the same trading idea. Now... how are they different?",
"updated": 1610466052450
"updated": 1610466052450,
"translations": [
{
"language": "ES",
"text": "¡Exactamente! Todas las estrategias presentan las mismas tres primeras condiciones en el desencadenante del evento. Esto muestra que todas las estrategias se basan en la misma idea de trading. Ahora... ¿en qué se diferencian?",
"updated": 1629591763135
}
]
}
]
}
@@ -4,23 +4,51 @@
"type": "Tutorial Step - Time Frame Analysys",
"definition": {
"icon": {
"project": "Foundations",
"name": "time-frame"
"name": "Time\\time-frame",
"project": "Foundations"
},
"text": "Each strategy specializes in specific market conditions by analyzing the state of the market on different time frames!"
"text": "Each strategy specializes in specific market conditions by analyzing the state of the market on different time frames!",
"translations": [
{
"language": "ES",
"text": "¡Cada estrategia se especializa en condiciones específicas del mercado analizando el estado del mercado en diferentes marcos de tiempo!",
"updated": 1629598321603
}
]
},
"paragraphs": [
{
"style": "Callout",
"text": "Take a look at the name of each strategy... 3H Down, 2H Down, 4H Up..."
"text": "Take a look at the name of each strategy... 3H Down, 2H Down, 4H Up...",
"translations": [
{
"language": "ES",
"text": "Echa un vistazo al nombre de cada estrategia... 3H Down, 2H Down, 4H Up...",
"updated": 1629598582815
}
]
},
{
"style": "Text",
"text": "If you study the conditions that define the trigger on event, you will notice that 3H Down referes to the fact that the particular strategy is triggered when the 3-hour time frame is in a downtrend."
"text": "If you study the conditions that define the trigger on event, you will notice that 3H Down referes to the fact that the particular strategy is triggered when the 3-hour time frame is in a downtrend.",
"translations": [
{
"language": "ES",
"text": "Si estudias las condiciones que definen el desencadenante del evento, notarás que 3H Down se refiere al hecho de que la estrategia particular se desencadena cuando el marco de tiempo de 3 horas está en una tendencia bajista.",
"updated": 1629598574248
}
]
},
{
"style": "Note",
"text": "Each of the strategies speciallizes on a certain time frame and trend!"
"text": "Each of the strategies speciallizes on a certain time frame and trend!",
"translations": [
{
"language": "ES",
"text": "¡Cada una de las estrategias se especializa en un cierto marco de tiempo y tendencia!",
"updated": 1629598547193
}
]
}
]
}
@@ -329,15 +329,22 @@ function newFoundationsFunctionLibraryUiObjectsFromNodes() {
pathName = rawPath[i][0]
pathType = rawPath[i][1]
pathNode = UI.projects.foundations.spaces.designSpace.workspace.getHierarchyHeadsByCodeNameAndNodeType( pathName, pathType )
// If reference parent is workspace node grab node
if (pathType === "Workspace") {
pathNode = UI.projects.foundations.spaces.designSpace.workspace.workspaceNode
}
// If Hierarchy Head is not located within the workspace abort reconnection
if (pathNode === undefined) {
console.log("[WARN] Abort reconnection saved path head node not found in current workspace", node)
return
}
continue
} else { // Walk through children nodes and find the next node from saved path
pathName = rawPath[i][0]
pathType = rawPath[i][1]
pathNode = getNextNodeFromPath(pathNode, pathName, pathType)
}
}
if (pathNode !== undefined ) {
@@ -347,6 +354,7 @@ function newFoundationsFunctionLibraryUiObjectsFromNodes() {
}
function getNextNodeFromPath(node, pathName, pathType) {
console.log("pathNode", node)
let schemaDocument = getSchemaDocument(node)
let nextNode = undefined
for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) {
@@ -157,7 +157,10 @@ function newWorkspace() {
let workspace = UI.projects.foundations.spaces.designSpace.workspace.workspaceNode
/* Validation if it is too early to save. */
if (thisObject.isInitialized === false) { return }
if (thisObject.isInitialized === false) {
console.log('Workspace not saved because it has not been initialized. =')
return
}
/* Validation of 2 sessions opened at the same time. */
let savedSessionTimestamp = window.localStorage.getItem('Session Timestamp')
@@ -73,6 +73,7 @@ function newCircularMenu() {
menuItem.visible = menuItemInitialValue.visible
menuItem.iconPathOn = menuItemInitialValue.iconPathOn
menuItem.iconPathOff = menuItemInitialValue.iconPathOff
menuItem.iconProject = menuItemInitialValue.iconProject
menuItem.rawRadius = menuItemInitialValue.rawRadius
menuItem.targetRadius = menuItemInitialValue.label
menuItem.currentRadius = menuItemInitialValue.currentRadius
@@ -9,6 +9,7 @@ function newCircularMenuItem() {
confirmationLabel: undefined,
iconOn: undefined,
iconOff: undefined,
iconProject: undefined,
icons: undefined,
currentIcon: undefined,
disableIfPropertyIsDefined: undefined,
@@ -94,6 +95,7 @@ function newCircularMenuItem() {
thisObject.container = undefined
thisObject.iconOn = undefined
thisObject.iconOff = undefined
thisObject.iconProject = undefined
thisObject.icons = undefined
thisObject.currentIcon = undefined
thisObject.payload = undefined
@@ -261,11 +263,18 @@ function newCircularMenuItem() {
thisObject.iconOn = UI.projects.foundations.spaces.designSpace.getIconByProjectAndName('Foundations', thisObject.secondaryIcon)
thisObject.iconOff = UI.projects.foundations.spaces.designSpace.getIconByProjectAndName('Foundations', thisObject.secondaryIcon)
} else {
if (thisObject.relatedUiObject !== undefined) {
if (thisObject.label === "Add Dependency Product Folder") { console.log ("Test") }
if (thisObject.relatedUiObject !== undefined && thisObject.iconProject !== undefined) {
thisObject.iconOn = UI.projects.foundations.spaces.designSpace.getIconByProjectAndType(thisObject.iconProject, thisObject.relatedUiObject)
thisObject.iconOff = UI.projects.foundations.spaces.designSpace.getIconByProjectAndType(thisObject.iconProject, thisObject.relatedUiObject)
} else if (thisObject.relatedUiObject !== undefined && thisObject.iconProject === undefined) {
thisObject.iconOn = UI.projects.foundations.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.relatedUiObject)
thisObject.iconOff = UI.projects.foundations.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.relatedUiObject)
} else {
if (thisObject.iconPathOn !== undefined && thisObject.iconPathOff !== undefined) {
if (thisObject.iconPathOn !== undefined && thisObject.iconPathOff !== undefined && thisObject.iconProject !== undefined) {
thisObject.iconOn = UI.projects.foundations.spaces.designSpace.getIconByProjectAndName(thisObject.iconProject, thisObject.iconPathOn)
thisObject.iconOff = UI.projects.foundations.spaces.designSpace.getIconByProjectAndName(thisObject.iconProject, thisObject.iconPathOff)
} else if (thisObject.iconPathOn !== undefined && thisObject.iconPathOff !== undefined && thisObject.iconProject === undefined) {
thisObject.iconOn = UI.projects.foundations.spaces.designSpace.getIconByProjectAndName('Foundations', thisObject.iconPathOn)
thisObject.iconOff = UI.projects.foundations.spaces.designSpace.getIconByProjectAndName('Foundations', thisObject.iconPathOff)
} else {
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#cdd4d5;}.cls-3{fill:#e6eaea;}.cls-4{fill:#365558;}.cls-5{fill:#fd6a33;}.cls-6{fill:#e3493c;}.cls-7{fill:none;}.cls-8{fill:#0295aa;}.cls-9{fill:#4acfd9;}</style></defs><title>airdrop-program</title><g id="Layer_15" data-name="Layer 15"><path class="cls-1" d="M166.66,502.09A14,14,0,0,0,180,512h2.34A17.34,17.34,0,0,1,166.66,502.09Z"/><path class="cls-1" d="M182.38,376.58H180a14,14,0,0,0-13.38,9.9A17.35,17.35,0,0,1,182.38,376.58Z"/><path class="cls-2" d="M170.05,390.57V498a10,10,0,0,0,10,10h76V380.57H180A10,10,0,0,0,170.05,390.57Z"/><path class="cls-3" d="M332,508a10,10,0,0,0,10-10V390.57a10,10,0,0,0-10-10H256V508Z"/><path class="cls-1" d="M332,376.58h-3.33a17.17,17.17,0,0,1,17.32,17V495a17.18,17.18,0,0,1-17.32,17H332a14,14,0,0,0,14-14V390.57A14,14,0,0,0,332,376.58Z"/><path class="cls-4" d="M166.05,390.57a14.2,14.2,0,0,1,.61-4.09,16.66,16.66,0,0,0-1.6,7.08V495a16.66,16.66,0,0,0,1.6,7.08,14.08,14.08,0,0,1-.61-4.08Z"/><path class="cls-4" d="M180,508a10,10,0,0,1-10-10V390.57a10,10,0,0,1,10-10h76v-4H182.38a17.35,17.35,0,0,0-15.72,9.9,14.2,14.2,0,0,0-.61,4.09V498a14.08,14.08,0,0,0,.61,4.08A17.34,17.34,0,0,0,182.38,512H256v-4Z"/><path class="cls-4" d="M346,495V393.56a17.17,17.17,0,0,0-17.32-17H256v4h76a10,10,0,0,1,10,10V498a10,10,0,0,1-10,10H256v4h72.63A17.18,17.18,0,0,0,346,495Z"/><path class="cls-1" d="M256,399.13v96.26a48.13,48.13,0,0,0,0-96.26Z"/><path class="cls-3" d="M207.87,447.26A48.12,48.12,0,0,0,256,495.39V399.13A48.13,48.13,0,0,0,207.87,447.26Z"/><path class="cls-5" d="M266.32,449.52a30.19,30.19,0,0,1-3.87-9.4c.45-4-1-8.92-4.16-9.4a3.57,3.57,0,0,0-2.29.47v25.75a31.72,31.72,0,0,1,3.21.89c3.41,2.31,8.31,3.55,10.4,1.2S269.61,452.58,266.32,449.52Z"/><path class="cls-6" d="M251.45,438.24a29.62,29.62,0,0,1-6.69,8c-3.75,1.67-7.36,5.19-6.19,8s6.52,3.08,10.19,2a32.12,32.12,0,0,1,7.26.72V431.17C253.78,432.41,252,435.6,251.45,438.24Z"/><path class="cls-5" d="M262.82,414.38c5.19.2,7.24,10.3,6.4,17.95A101.36,101.36,0,0,0,276,451.08a7.72,7.72,0,0,0,3.29,3.16,40.75,40.75,0,0,1-3.5-20c3.3-8.76,1.83-20.59-3.12-23.35a11.49,11.49,0,0,0-15.19,4.61.76.76,0,0,0-.09.18A7.69,7.69,0,0,1,262.82,414.38Z"/><path class="cls-6" d="M233.46,436.11c-9.55,1.64-19.46,8.76-19.46,14.23a11.1,11.1,0,0,0,11.77,10.33h.15a7.56,7.56,0,0,1-3.61-4c-2.5-4,5.39-10.94,12.84-14.19,2.37-1,12.09-13,13.46-15a7.74,7.74,0,0,0,1.2-4.36A43.34,43.34,0,0,1,233.46,436.11Z"/><path class="cls-5" d="M282.81,465.52a2,2,0,0,0-.21-.3,7.16,7.16,0,0,1-1.61,5.11c-2.75,4-12.77.92-19.41-3.68q-2.76-.76-5.58-1.41v5.56c.22.15.45.28.68.43,6.28,7.17,17.61,12,22.56,9.08A10.48,10.48,0,0,0,282.81,465.52Z"/><path class="cls-6" d="M241.35,463a7.63,7.63,0,0,0-4.49,1.17A44,44,0,0,1,256,470.82v-5.57A112.68,112.68,0,0,0,241.35,463Z"/><path class="cls-7" d="M73.94,197.32l170.45,155L175.44,199.91C125.06,158.21,84.92,187.52,73.94,197.32Z"/><path class="cls-7" d="M336.66,199.69,267.61,352.34,437.77,197.59C383.41,155.17,341.58,194.68,336.66,199.69Z"/><path class="cls-8" d="M230.08,9.88C143.71,22.49,76.44,97.11,72.29,188.45c15.56-12,55-34.3,102.48.78C176.13,104.33,198.58,34.8,230.08,9.88Z"/><path class="cls-9" d="M337.22,188.67c15.34-12,54.87-34.67,102.52.37C435.85,97.43,368.48,22.51,281.92,9.88,313.35,34.75,335.77,104,337.22,188.67Z"/><path class="cls-9" d="M256,170.3h.94l.65,0,1.43,0,.81,0,1.31.05.88,0,1.25.07.94.06,1.22.08,1,.08,1.22.1,1,.1,1.22.12,1,.11,1.22.14,1,.13,1.23.17,1,.14,1.24.19,1.05.17,1.25.2,1.05.19,1.27.23,1.05.2,1.29.26,1.06.22,1.3.28L287,174l1.32.31,1.06.25,1.34.34,1.06.28,1.37.37,1,.29,1.39.4,1,.31,1.44.44,1,.32,1.51.49,1,.32,1.57.54.92.32,1.72.63.78.28c.7.26,1.39.53,2.09.81l.43.16,2.56,1,.1,0,2.44,1,.78.34,1.78.8,1,.45,1.59.74,1.07.52,1.52.74,1.12.57c.49.25,1,.49,1.48.75l1.17.61,1.44.76,1.2.66,1,.55C327.77,90.84,294.83,8,256,8h0Z"/><path class="cls-8" d="M184.72,188.82l.7-.39.71-.4,1.21-.66.73-.39c.36-.2.73-.39,1.1-.58l.92-.48,1.11-.56.73-.36,1.61-.78.76-.35c.51-.25,1-.49,1.58-.73l.79-.36,1.55-.68.73-.31,2-.84.76-.31,2-.8.64-.24,2-.75.72-.25c.78-.28,1.58-.56,2.4-.83l.72-.24,2.54-.82.37-.11,2.58-.77.65-.19,2.82-.76.63-.16c1-.26,2-.52,3.07-.76a140.84,140.84,0,0,1,32-3.67H256V8c-38.77,0-71.67,82.58-73.25,182l.35-.2.62-.37Z"/><path class="cls-4" d="M258,371.78l-.42.2Z"/><path class="cls-4" d="M257.3,372.07a3.17,3.17,0,0,1-.44.12A3.17,3.17,0,0,0,257.3,372.07Z"/><path class="cls-4" d="M256.66,372.23a3.68,3.68,0,0,1-.66.06A3.68,3.68,0,0,0,256.66,372.23Z"/><path class="cls-4" d="M253.88,371.68a4.19,4.19,0,0,1-.54-.4A4.19,4.19,0,0,0,253.88,371.68Z"/><path class="cls-4" d="M254.48,372a3.42,3.42,0,0,1-.43-.21A3.42,3.42,0,0,0,254.48,372Z"/><path class="cls-4" d="M255.14,372.19a3.17,3.17,0,0,1-.44-.12A3.17,3.17,0,0,0,255.14,372.19Z"/><path class="cls-4" d="M336.23,200.13l-.06.05a3.7,3.7,0,0,1-.46.42h0a3.07,3.07,0,0,1-.42.28l-.08,0L335,201l-.41.17-.18.06-.48.11-.12,0a4.29,4.29,0,0,1-.62,0h-.1a4.43,4.43,0,0,1-.51-.06l-.19,0a3.45,3.45,0,0,1-.43-.12l-.18-.07a5,5,0,0,1-.57-.28c-1-.62-2-Line truncated

After

Width:  |  Height:  |  Size: 22 KiB

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#365558;fill-rule:evenodd;}.cls-2{fill:#e6eaea;}.cls-3{fill:#fff;}</style></defs><title>github-program</title><path class="cls-1" d="M384,512H128A128,128,0,0,1,0,384V128A128,128,0,0,1,128,0H384A128,128,0,0,1,512,128V384A128,128,0,0,1,384,512"/><path class="cls-1" d="M240,144H384A72,72,0,0,0,391.36.37C388.91.23,386.49,0,384,0H128A128,128,0,0,0,0,128V384C0,251.45,107.45,144,240,144"/><path class="cls-1" d="M384,256A128,128,0,1,0,512,384V128A128,128,0,0,1,384,256"/><path class="cls-2" d="M94.22,185.82a176.16,176.16,0,0,0,91.51,231.72A16,16,0,0,0,208,402.81V376h-3.76a64,64,0,0,1-54.88-31.07l-1.25-2.07A14.11,14.11,0,0,0,136,336a8,8,0,0,1,0-16h0a32,32,0,0,1,25.59,12.79h0A48,48,0,0,0,200,352h8.67a48,48,0,0,1,13.39-25.94c1-1,2-1.95,3.11-2.85A1.82,1.82,0,0,0,224,320h0a80,80,0,0,1-63.91-128.12,77.29,77.29,0,0,1,.77-36.87l1.36-5.08a8,8,0,0,1,9.8-5.66l5.08,1.36a77.38,77.38,0,0,1,30.4,16.07A80.85,80.85,0,0,1,224,160h32V79.72A176.19,176.19,0,0,0,94.22,185.82Z"/><path class="cls-3" d="M325.93,94.3A175.57,175.57,0,0,0,256,79.72V160h32a81,81,0,0,1,16.51,1.7,77.32,77.32,0,0,1,30.4-16.07l5.08-1.36a8,8,0,0,1,9.79,5.66l1.36,5.08a77.12,77.12,0,0,1,.77,36.86A80,80,0,0,1,288,320h0a1.82,1.82,0,0,0-1.16,3.21c1.07.9,2.11,1.85,3.11,2.85A48,48,0,0,1,304,360s0,23.91.13,42.81a15.86,15.86,0,0,0,22.08,14.6,176.16,176.16,0,0,0-.28-323.11Z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#365558;}.cls-2{fill:#f0353d;}.cls-3{fill:#fd6a33;}.cls-4{fill:#0295aa;}.cls-5{fill:#4acfd9;}.cls-6{fill:#e6eaea;}.cls-7{fill:#cdd4d5;}.cls-8{fill:#9baaab;}.cls-9{fill:#ff8c29;}.cls-10{fill:#fff;}</style></defs><title>influencer-program</title><g id="Layer_2" data-name="Layer 2"><polygon class="cls-1" points="408.9 342.47 408.9 243.3 342.9 243.3 342.9 258.31 393.89 258.31 393.89 342.47 408.9 342.47"/><rect class="cls-1" x="312.46" y="243.3" width="15.43" height="15.02"/><rect class="cls-1" x="312.46" y="180.22" width="15.75" height="15.02"/><polygon class="cls-1" points="382.01 122.49 349.13 180.22 343.22 180.22 343.22 195.24 357.86 195.24 395.06 129.92 382.01 122.49"/><rect class="cls-1" x="264.91" y="101.18" width="15.02" height="16.02"/><polygon class="cls-1" points="264.91 86.16 279.92 86.16 279.92 45.62 194.34 45.62 194.34 60.63 264.91 60.63 264.91 86.16"/><path class="cls-2" d="M126.54,15.12h-.07a28.51,28.51,0,0,0-20.29,8.48l-9.89,10L86,23.4a28.47,28.47,0,0,0-20.15-8.28h-.21A28.49,28.49,0,0,0,45.38,23.7a28.87,28.87,0,0,0,.31,40.72L68,86.91l69.59-69.59A28.62,28.62,0,0,0,126.54,15.12Z"/><path class="cls-3" d="M146.89,64.22a28.82,28.82,0,0,0-9.31-46.9L68,86.91l28.24,28.48Z"/><path class="cls-3" d="M157.4,12.86a44.43,44.43,0,0,0-8.65-6.71l-5.53,5.53a36.32,36.32,0,0,1,9,57.82L99.23,123l-3,3L62.68,92.22l-5.31,5.31,38.88,39.2L157.56,74.8a43.53,43.53,0,0,0,12.72-32h0A43.72,43.72,0,0,0,157.4,12.86Z"/><path class="cls-2" d="M40.41,69.76A36.27,36.27,0,0,1,91.28,18.05l5,4.9,4.61-4.65a36.22,36.22,0,0,1,42.37-6.62l5.53-5.53A43.46,43.46,0,0,0,126.54.1h-.11A43.41,43.41,0,0,0,96.19,12.36,43.39,43.39,0,0,0,65.85.1h-.32A43.45,43.45,0,0,0,34.68,13.17a43.89,43.89,0,0,0,.4,61.88L57.37,97.53l5.31-5.31Z"/><path class="cls-3" d="M146.8,23.5a28.82,28.82,0,0,1,.09,40.72L96.23,115.39,68,86.91l-5.31,5.31,33.56,33.84,3-3,53-53.54a36.33,36.33,0,0,0-9-57.82l-5.64,5.64A28.59,28.59,0,0,1,146.8,23.5Z"/><path class="cls-2" d="M100.85,18.3,96.24,23l-5-4.9A36.27,36.27,0,0,0,40.41,69.76L62.68,92.22,68,86.91,45.69,64.42a28.87,28.87,0,0,1-.31-40.72,28.49,28.49,0,0,1,20.26-8.58h.21A28.47,28.47,0,0,1,86,23.4L96.29,33.56l9.89-10a28.51,28.51,0,0,1,20.29-8.48h.07a28.62,28.62,0,0,1,11,2.2l5.64-5.64A36.22,36.22,0,0,0,100.85,18.3Z"/><polygon class="cls-4" points="415.03 86.55 435.05 66.53 440.36 71.84 486 26.2 346.49 70.95 407.91 104.29 407.91 104.29 420.34 91.86 415.03 86.55"/><polygon class="cls-5" points="486 26.2 486 26.2 440.36 71.84 445.67 77.15 425.65 97.17 420.34 91.86 407.91 104.29 441.25 165.71 486 26.2"/><rect class="cls-6" x="418.85" y="80.75" width="28.31" height="7.51" transform="translate(67.07 330.93) rotate(-45)"/><rect class="cls-7" x="413.54" y="75.44" width="28.31" height="7.51" transform="translate(69.27 325.62) rotate(-45)"/><polygon class="cls-5" points="497.61 14.59 497.61 14.59 443.04 184.73 402.38 109.83 402.37 109.83 396.84 115.36 396.84 115.36 444.82 203.75 509.21 2.99 497.61 14.59"/><polygon class="cls-4" points="327.47 69.16 497.61 14.59 509.21 2.99 509.21 2.98 308.45 67.38 396.84 115.36 402.37 109.83 327.47 69.16"/><polygon class="cls-4" points="402.37 109.83 407.91 104.29 407.91 104.29 346.49 70.95 486 26.2 497.61 14.59 327.47 69.16 402.37 109.83"/><polygon class="cls-5" points="486 26.2 441.25 165.71 407.91 104.29 402.37 109.83 402.38 109.83 443.04 184.73 497.61 14.59 497.61 14.59 486 26.2 486 26.2"/><rect class="cls-6" x="87.47" y="55.42" width="28.31" height="7.51" transform="translate(-12.08 89.19) rotate(-45)"/><rect class="cls-7" x="82.16" y="50.11" width="28.31" height="7.51" transform="translate(-9.88 83.88) rotate(-45)"/><path class="cls-4" d="M15.65,241.94v11.82A10.24,10.24,0,0,0,25.88,264H42V231.7H25.88A10.24,10.24,0,0,0,15.65,241.94Z"/><polygon class="cls-4" points="280.39 160.74 259.93 160.74 259.93 188.73 280.39 163.92 280.39 160.74"/><polygon class="cls-5" points="252.42 207.33 252.42 222.34 259.93 222.34 259.93 334.96 280.39 334.96 280.39 163.92 259.93 188.73 259.93 207.33 252.42 207.33"/><polygon class="cls-4" points="126.83 320.41 126.83 350.06 151.29 320.41 126.83 320.41"/><path class="cls-5" d="M182.78,443.77V320.41H151.29l-24.46,29.65v93.71Zm-34.9-102.9h15v15h-15Zm15,30V411h-15V370.9Z"/><polygon class="cls-5" points="244.91 207.33 244.91 206.93 163.68 305.39 197.79 305.39 217.74 305.39 244.91 326.94 244.91 222.34 252.41 222.34 252.41 207.33 244.91 207.33"/><path class="cls-4" d="M244.91,168.76l-27.17,21.55H85a28,28,0,0,0-28,28v59.14a28,28,0,0,0,28,28h78.66l81.23-98.46ZM150.07,286.65H82.65v-15h67.42Zm0-31H82.65v-15h67.42Zm0-31H82.65v-15h67.42Z"/><rect class="cls-5" x="250.37" y="214.83" height="7.51"/><polygon class="cls-4" points="154.8 486.07 175.27 458.79 134.34 458.79 154.8 486.07"/><rect class="cls-6" x="147.88" y="370.9" width="15.02" height="40.04"/><rect class="cls-6" x="147.88" y="340.87" width="15.02" height="15.02"/><rect class="cls-8" x="82.65" y="209.63" width="67.42" height="15.02"/><rect class="clLine truncated

After

Width:  |  Height:  |  Size: 10 KiB

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#faab18;}.cls-2{fill:none;}.cls-3{fill:#0295aa;}.cls-4{fill:#e6eaea;}.cls-5{fill:#f0353d;}.cls-6{fill:#ff8c29;}.cls-7{fill:#9baaab;}.cls-8{fill:#4acfd9;}.cls-9{fill:#fd6a33;}.cls-10{fill:#ffd1a9;}</style></defs><title>mentorship-program</title><path class="cls-1" d="M250.08,381a50.32,50.32,0,0,0,5.92.36h.29V381Z"/><path class="cls-2" d="M256,488.57l-27.22,20.76a13,13,0,0,1-7.87,2.67h35.21l0-23.31Z"/><path class="cls-3" d="M171.71,376.86a18.91,18.91,0,0,1-15.41-12.8,18.49,18.49,0,0,1,4.84-19.27,3.52,3.52,0,0,0-.6-5.57,19,19,0,0,1-6.14-6.15H132.89a7.67,7.67,0,0,1-7.72,7.62H88.08A13.88,13.88,0,0,1,74.33,329a28.16,28.16,0,0,0-23.86-23.51A13.79,13.79,0,0,1,38.64,292V86.76A13.79,13.79,0,0,1,50.47,73.22,28.16,28.16,0,0,0,74.33,49.71,13.87,13.87,0,0,1,88.07,38.06H256.73l0-30.45H20.6A12.8,12.8,0,0,0,7.73,20.3V358.45A12.8,12.8,0,0,0,20.6,371.13H134.81a7.67,7.67,0,0,1,7.73,7.61h31.87c0-.05,0-.1-.08-.14A3.54,3.54,0,0,0,171.71,376.86Z"/><path class="cls-4" d="M151.75,321.36a18.71,18.71,0,0,1,12.37-15.67,3.52,3.52,0,0,0,2.19-2.25,3.46,3.46,0,0,0-.43-3.08,18.46,18.46,0,0,1-.67-19.84A19.05,19.05,0,0,1,183,271.16a3.55,3.55,0,0,0,2.93-1.17,3.47,3.47,0,0,0,.88-3,18.54,18.54,0,0,1,7.58-18.39,19.19,19.19,0,0,1,20.1-1.43,3.59,3.59,0,0,0,3.16.1,3.53,3.53,0,0,0,2-2.38,18.84,18.84,0,0,1,14.53-13.76,19.13,19.13,0,0,1,18.95,6.75,3.58,3.58,0,0,0,2.84,1.36l.47,0,.07-51.88H99.41a7.61,7.61,0,1,1,0-15.22H256.56l0-22.27H99.41a7.61,7.61,0,1,1,0-15.22h157.2l0-28H153.06a7.61,7.61,0,1,1,0-15.22h103.6l0-38.1H89.4A43.63,43.63,0,0,1,54.08,88.07V290.68A43.63,43.63,0,0,1,89.4,325.46h35.77a7.66,7.66,0,0,1,7.72,7.61H154.4A18.47,18.47,0,0,1,151.75,321.36Z"/><path class="cls-5" d="M238.89,424.93a3.65,3.65,0,0,0-5.56-1.16,19.18,19.18,0,0,1-9.86,4.22v66.14l24.65-18.8a13,13,0,0,1,7.88-2.65h.17l.05-37.28H256A19,19,0,0,1,238.89,424.93Z"/><path class="cls-6" d="M211.21,378.74h-21a18.48,18.48,0,0,1-1.28,8.62,3.46,3.46,0,0,0,.67,3.71,3.57,3.57,0,0,0,3.68,1.05A19.16,19.16,0,0,1,209.65,395a18.63,18.63,0,0,1,6.09,7.33V382.68C214.17,381.44,212.65,380.12,211.21,378.74Z"/><path class="cls-6" d="M191.49,333.07H175.24a18.51,18.51,0,0,1-3.32,22.63,3.44,3.44,0,0,0-.92,3.66,3.52,3.52,0,0,0,2.93,2.43,19,19,0,0,1,13.78,9.2,18.52,18.52,0,0,1,2.48,7.75h21A62.87,62.87,0,0,1,191.49,333.07Z"/><path class="cls-6" d="M256,269.52l.43,0,0-15.09-.45,0a19,19,0,0,1-15-7.17,3.59,3.59,0,0,0-3.6-1.28,3.53,3.53,0,0,0-2.76,2.62,18.77,18.77,0,0,1-10.73,12.54,19.2,19.2,0,0,1-16.64-.54,3.58,3.58,0,0,0-3.82.27,3.46,3.46,0,0,0-1.44,3.5,18.48,18.48,0,0,1-4.63,15.76A19.08,19.08,0,0,1,182,286.35a3.55,3.55,0,0,0-3.38,1.78,3.42,3.42,0,0,0,.13,3.77A18.47,18.47,0,0,1,181,308.15,18.82,18.82,0,0,1,169.46,320a3.54,3.54,0,0,0-.67,6.37,18.76,18.76,0,0,1,6.45,6.72h16.25C191.49,298,220.43,269.52,256,269.52Z"/><path class="cls-6" d="M256,396.62a64.84,64.84,0,0,1-40.26-13.94v19.65a18.44,18.44,0,0,1,1.76,7.13,3.49,3.49,0,0,0,2.15,3.13,3.58,3.58,0,0,0,3.79-.52,19.15,19.15,0,0,1,12.16-4.35,20.29,20.29,0,0,1,4,.41,18.94,18.94,0,0,1,13.14,10.08,3.55,3.55,0,0,0,3.25,2h.24l0-23.57Z"/><path class="cls-5" d="M256.29,378.74H240a49.76,49.76,0,0,0,10.1,2.3h6.21Z"/><path class="cls-5" d="M256.35,333.07H206.94a48.46,48.46,0,0,0,33,45.67h16.31Z"/><path class="cls-5" d="M256.41,284.76H256c-27.05,0-49.06,21.67-49.06,48.32h49.41Z"/><path class="cls-3" d="M0,20.3V358.45a20.45,20.45,0,0,0,20.6,20.29H142.54a7.67,7.67,0,0,0-7.73-7.61H20.6A12.8,12.8,0,0,1,7.73,358.45V20.3A12.8,12.8,0,0,1,20.6,7.61H256.77V0H20.6A20.46,20.46,0,0,0,0,20.3Z"/><path class="cls-3" d="M74.33,49.71A28.16,28.16,0,0,1,50.47,73.22,13.79,13.79,0,0,0,38.64,86.76V292a13.79,13.79,0,0,0,11.83,13.54A28.16,28.16,0,0,1,74.33,329a13.88,13.88,0,0,0,13.75,11.66h37.09a7.67,7.67,0,0,0,7.72-7.62H88.07A6.1,6.1,0,0,1,82,327.94a35.77,35.77,0,0,0-30.41-30,6.07,6.07,0,0,1-5.21-6V86.76a6.07,6.07,0,0,1,5.21-6A35.76,35.76,0,0,0,82,50.81a6.1,6.1,0,0,1,6.09-5.14H256.72V38.06H88.07A13.87,13.87,0,0,0,74.33,49.71Z"/><path class="cls-4" d="M125.17,325.46H89.4a43.63,43.63,0,0,0-35.32-34.78V88.07A43.63,43.63,0,0,0,89.4,53.28H256.71V45.67H88.07A6.1,6.1,0,0,0,82,50.81a35.76,35.76,0,0,1-30.41,30,6.07,6.07,0,0,0-5.21,6V292a6.07,6.07,0,0,0,5.21,6,35.77,35.77,0,0,1,30.41,30,6.1,6.1,0,0,0,6.09,5.13h44.82A7.66,7.66,0,0,0,125.17,325.46Z"/><path class="cls-3" d="M226.77,381c-1.21-.72-2.39-1.49-3.54-2.3h-12c1.44,1.38,3,2.7,4.53,3.94V381Z"/><path class="cls-3" d="M199.22,333.07h-7.73a62.87,62.87,0,0,0,19.72,45.67h12A55.61,55.61,0,0,1,199.22,333.07Z"/><path class="cls-3" d="M256,277.14h.42v-7.61l-.43,0c-35.57,0-64.51,28.51-64.51,63.55h7.73C199.22,302.18,224.64,277.14,256,277.14Z"/><path class="cls-3" d="M256,389a57.17,57.17,0,0,1-29.23-8h-11v1.64A64.84,64.84,0,0,0,256,396.62h.27V389Z"/><path class="cls-3" d="M240,378.74H223.23c1.15.81,2.33,1.58,3.54,2.3h23.31A49.76,49.76,0,0,1,240,378.74Z"/><path class="cls-3" d="M206.94,333.07h-7.72a55.61,55.61,0,0,0,24,45.67H240A48.46,48.46,0,0,1,2Line truncated

After

Width:  |  Height:  |  Size: 18 KiB

Loaded 100 of 135 files, more files were not shown because too many files have changed in this diff. Show more