Skip to content

Commit

Permalink
Rupato/BOT-2196/feat: Implementation--for-new-accumulator-blocks (bin…
Browse files Browse the repository at this point in the history
…ary-com#16848)

* feat: Implementation--for-new-accumulator-blocks

* fix: build issue and removed comments

* fix: removed console.logs

* fix: for accumulators stats

* fix: added comment

* fix: bug fixes for accumulators

* fix: code refactored

* fix: for parent block

* fix: cypress test case

* fix: login user check

* fix: for proposal request

* fix: proposal request

* fix: proposal request

* fix: reverted change for sell conditions
  • Loading branch information
rupato-deriv committed Sep 26, 2024
1 parent a9cb798 commit 47ca772
Show file tree
Hide file tree
Showing 13 changed files with 344 additions and 13 deletions.
39 changes: 39 additions & 0 deletions packages/bot-skeleton/src/scratch/accumulators-proposal-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { api_base } from '../services/api';
import DBotStore from './dbot-store';

export const DEFAULT_PROPOSAL_REQUEST = {
amount: undefined,
basis: 'stake',
contract_type: 'ACCU',
currency: undefined,
symbol: undefined,
growth_rate: undefined,
proposal: 1,
subscribe: 1,
};

export const forgetAccumulatorsProposalRequest = async instance => {
if (instance && !instance.is_bot_running) {
await api_base?.api?.send({ forget_all: 'proposal' });
instance.subscription_id_for_accumulators = null;
instance.is_proposal_requested_for_accumulators = false;
window.Blockly.accumulators_request = {};
}
};

export const handleProposalRequestForAccumulators = instance => {
const top_parent_block = instance?.getTopParent();
const market_block = top_parent_block?.getChildByType('trade_definition_market');
const symbol = market_block?.getFieldValue('SYMBOL_LIST');
const currency = DBotStore.instance.client.currency;
const growth_rate = instance?.getFieldValue('GROWTHRATE_LIST') || 0.01;
const amount = instance?.childBlocks_?.[0]?.getField('NUM')?.getValue() || 0;
const proposal_request = {
...DEFAULT_PROPOSAL_REQUEST,
amount,
currency,
symbol,
growth_rate,
};
window.Blockly.accumulators_request = proposal_request;
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ import './check_direction';
import './tick_analysis';
import './last_digit';
import './lastDigitList';
import './stat';
import './stat_list';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { localize } from '@deriv/translations';
import { modifyContextMenu } from '../../../utils';

Blockly.Blocks.stat = {
init() {
this.jsonInit(this.definition());
},
definition() {
return {
message0: localize('Current Stat'),
output: 'Number',
outputShape: Blockly.OUTPUT_SHAPE_ROUND,
colour: Blockly.Colours.Base.colour,
colourSecondary: Blockly.Colours.Base.colourSecondary,
colourTertiary: Blockly.Colours.Base.colourTertiary,
tooltip: localize('Returns the Current Stat'),
category: Blockly.Categories.Tick_Analysis,
};
},
meta() {
return {
display_name: localize('Current Stat'),
description: localize('This block gives you the Current Stat value.'),
};
},
customContextMenu(menu) {
modifyContextMenu(menu);
},
};

Blockly.JavaScript.javascriptGenerator.forBlock.stat = () => [
'Bot.getCurrentStat()',
Blockly.JavaScript.javascriptGenerator.ORDER_ATOMIC,
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { localize } from '@deriv/translations';
import { modifyContextMenu } from '../../../utils';

Blockly.Blocks.stat_list = {
init() {
this.jsonInit(this.definition());
},
definition() {
return {
message0: localize('Current stat list'),
output: 'Array',
outputShape: Blockly.OUTPUT_SHAPE_ROUND,
colour: Blockly.Colours.Base.colour,
colourSecondary: Blockly.Colours.Base.colourSecondary,
colourTertiary: Blockly.Colours.Base.colourTertiary,
tooltip: localize('Returns the list of last digits of 1000 recent tick values'),
category: Blockly.Categories.Tick_Analysis,
};
},
meta() {
return {
display_name: localize('Current stat list'),
description: localize('This block gives you a list of the cuurent stats of the last 1000 tick values.'),
};
},
customContextMenu(menu) {
modifyContextMenu(menu);
},
};

Blockly.JavaScript.javascriptGenerator.forBlock.stat_list = () => [
'Bot.getStatList()',
Blockly.JavaScript.javascriptGenerator.ORDER_ATOMIC,
];
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ import './epoch';
import './timeout';
import './todatetime';
import './totimestamp';
import './tickdelay';
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { localize } from '@deriv/translations';
import { modifyContextMenu, evaluateExpression } from '../../../../utils';
import DBotStore from '../../../../dbot-store';

Blockly.Blocks.tick_delay = {
init() {
this.jsonInit(this.definition());
const { client } = DBotStore.instance;
if (client && client.is_logged_in) {
this.workspace_to_code = Blockly.JavaScript.javascriptGenerator.workspaceToCode(Blockly.derivWorkspace);
}
},
definition() {
return {
message0: localize('{{ stack_input }} Run after {{ number }} tick(s)', {
stack_input: '%1',
number: '%2',
}),
args0: [
{
type: 'input_statement',
name: 'TICKDELAYSTACK',
},
{
type: 'input_value',
name: 'TICKDELAYVALUE',
},
],
colour: Blockly.Colours.Base.colour,
colourSecondary: Blockly.Colours.Base.colourSecondary,
colourTertiary: Blockly.Colours.Base.colourTertiary,
previousStatement: null,
nextStatement: null,
tooltip: localize('Run the blocks inside after a given number of ticks'),
category: Blockly.Categories.Time,
};
},
meta() {
return {
display_name: localize('Tick Delayed run'),
description: localize(
'This block delays execution for a given number of ticks. You can place any blocks within this block. The execution of other blocks in your strategy will be paused until the instructions in this block are carried out.'
),
};
},
customContextMenu(menu) {
modifyContextMenu(menu);
},
getRequiredValueInputs() {
return {
TICKDELAYVALUE: input_value => {
const evaluated_result = evaluateExpression(input_value);
if (evaluated_result === 'invalid_input') {
// this was done to check if any equation or varible assignment is present in the code.
if (this.workspace_to_code && this.workspace_to_code.includes(input_value)) {
return false;
}
this.error_message = localize('Invalid Input {{ input_value }}.', { input_value });
return true;
}

if (evaluated_result < 0) {
this.error_message = localize('Values cannot be negative. Provided value: {{ input_value }}.', {
input_value,
});
return true;
}
},
};
},
};

Blockly.JavaScript.javascriptGenerator.forBlock.tick_delay = block => {
const stack = Blockly.JavaScript.javascriptGenerator.statementToCode(block, 'TICKDELAYSTACK');
const ticks_value =
Blockly.JavaScript.javascriptGenerator.valueToCode(
block,
'TICKDELAYVALUE',
Blockly.JavaScript.javascriptGenerator.ORDER_ATOMIC
) || '1';

const code = `Bot.getDelayTickValue(${ticks_value})\n${stack}\n`;
return code;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import DBotStore from '../../../dbot-store';
import { modifyContextMenu, runGroupedEvents, runIrreversibleEvents } from '../../../utils';
import { config } from '../../../../constants/config';
import ApiHelpers from '../../../../services/api/api-helpers';
import { handleProposalRequestForAccumulators } from '../../../accumulators-proposal-handler';

Blockly.Blocks.trade_definition_accumulator = {
init() {
Expand Down Expand Up @@ -101,7 +102,7 @@ Blockly.Blocks.trade_definition_accumulator = {
if (!this.workspace || Blockly.derivWorkspace.isFlyoutVisible || this.workspace.isDragging()) {
return;
}

handleProposalRequestForAccumulators(this);
const trade_definition_block = this.workspace
.getAllBlocks(true)
.find(block => block.type === 'trade_definition');
Expand Down
12 changes: 8 additions & 4 deletions packages/bot-skeleton/src/scratch/dbot.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DBotStore from './dbot-store';
import { isAllRequiredBlocksEnabled, updateDisabledBlocks, validateErrorOnBlockDelete } from './utils';

import { loadBlockly } from './blockly';
import { forgetAccumulatorsProposalRequest } from './accumulators-proposal-handler';

class DBot {
constructor() {
Expand Down Expand Up @@ -53,6 +54,8 @@ class DBot {
const symbol = market_block.getFieldValue('SYMBOL_LIST');
const category = this.getFieldValue('TRADETYPECAT_LIST');
const trade_type = this.getFieldValue('TRADETYPE_LIST');
const is_trade_type_accumulator = trade_type === 'accumulator';
if (!is_trade_type_accumulator) forgetAccumulatorsProposalRequest(that);

if (is_symbol_list_change) {
contracts_for.getTradeTypeCategories(market, submarket, symbol).then(categories => {
Expand Down Expand Up @@ -367,6 +370,7 @@ class DBot {
this.interpreter = null;
this.interpreter = Interpreter();
await this.interpreter.bot.tradeEngine.watchTicks(this.symbol);
forgetAccumulatorsProposalRequest(this);
}

/**
Expand Down Expand Up @@ -400,11 +404,10 @@ class DBot {
* Disable blocks outside of any main or independent blocks.
*/
disableStrayBlocks() {
const isMainBlock = block_type => config.mainBlocks.indexOf(block_type) >= 0;
const top_blocks = this.workspace.getTopBlocks();

top_blocks.forEach(block => {
if (!isMainBlock() && !block.isIndependentBlock()) {
if (!block.isMainBlock() && !block.isIndependentBlock()) {
this.disableBlocksRecursively(block);
}
});
Expand All @@ -416,8 +419,9 @@ class DBot {
* Disable blocks and their optional children.
*/
disableBlocksRecursively(block) {
if (block.nextConnection?.targetConnection) {
this.disableBlocksRecursively(block.nextConnection.targetConnection.sourceBlock_);
block.setDisabled(true);
if (block?.outputConnection?.targetConnection) {
this.disableBlocksRecursively(block?.outputConnection?.sourceBlock_);
}
}

Expand Down
25 changes: 17 additions & 8 deletions packages/bot-skeleton/src/scratch/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -658,14 +658,12 @@ const download_option = {
};

export const excludeOptionFromContextMenu = (menu, exclude_items) => {
if (exclude_items && exclude_items.length > 0) {
for (let i = menu.length - 1; i >= 0; i--) {
const menu_text = localize(menu[i].text);
if (exclude_items.includes(menu_text)) {
menu.splice(i, 1);
} else {
menu[i].text = menu_text;
}
for (let i = 0; i <= menu.length - 1; i++) {
const menu_text = localize(menu[i].text);
if (exclude_items.includes(menu_text)) {
menu.splice(i, 1);
} else {
menu[i].text = menu_text;
}
}
};
Expand Down Expand Up @@ -706,3 +704,14 @@ export const modifyContextMenu = (menu, add_new_items = []) => {
}
}
};

export const evaluateExpression = value => {
if (!value) return 'invalid_input';
try {
// eslint-disable-next-line no-new-func
const result = new Function(`return ${value.trim()}`)();
return isNaN(result) ? 'invalid_input' : result;
} catch (e) {
return 'invalid_input';
}
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const getTicksInterface = tradeEngine => {
return {
getDelayTickValue: (...args) => tradeEngine.getDelayTickValue(...args),
getCurrentStat: (...args) => tradeEngine.getCurrentStat(...args),
getStatList: (...args) => tradeEngine.getStatList(...args),
getLastTick: (...args) => tradeEngine.getLastTick(...args),
getLastDigit: (...args) => tradeEngine.getLastDigit(...args),
getTicks: (...args) => tradeEngine.getTicks(...args),
Expand Down
Loading

0 comments on commit 47ca772

Please sign in to comment.