Skip to content

Commit

Permalink
fixes for Strategy Tab. v.2.6
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrei Kuminov committed Apr 19, 2023
1 parent 6bcbc45 commit d444e40
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 65 deletions.
14 changes: 7 additions & 7 deletions content_scripts/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const action = {
action.saveParameters = async () => {
const strategyData = await tv.getStrategy(null, true)
if(!strategyData || !strategyData.hasOwnProperty('name') || !strategyData.hasOwnProperty('properties') || !strategyData.properties) {
await ui.showWarningPopup('Please open the indicator (strategy) parameters window before saving them to a file.')
await ui.showErrorPopup('The current indicator/strategy do not contain inputs that can be saved.')
// await ui.showWarningPopup('Please open the indicator (strategy) parameters window before saving them to a file.')
return
}
let strategyParamsCSV = `Name,Value\n"__indicatorName",${JSON.stringify(strategyData.name)}\n`
Expand All @@ -30,7 +31,7 @@ action.uploadStrategyTestParameters = async () => {
action.getStrategyTemplate = async () => {
const strategyData = await tv.getStrategy()
if(!strategyData || !strategyData.hasOwnProperty('name') || !strategyData.hasOwnProperty('properties') || !strategyData.properties) {
await ui.showErrorPopup('It was not possible to find a strategy with parameters among the indicators. Add it to the chart and try again.')
await ui.showErrorPopup('The current strategy do not contain inputs, than can be saved')
} else {
const paramRange = model.getStrategyRange(strategyData)
console.log(paramRange)
Expand Down Expand Up @@ -69,7 +70,6 @@ action.downloadStrategyTestResults = async () => {


action.testStrategy = async (request, isDeepTest = false) => {
console.log('request', request)
try {
const strategyData = await action._getStrategyData()
const [allRangeParams, paramRange, cycles] = await action._getRangeParams(strategyData)
Expand Down Expand Up @@ -133,9 +133,9 @@ action.testStrategy = async (request, isDeepTest = false) => {
action._getRangeParams = async (strategyData) => {
let paramRange = await model.getStrategyParameters(strategyData)
console.log('paramRange', paramRange)
if(!paramRange)
throw new Error('Error get changed strategy parameters')
// return
if(paramRange === null)
// throw new Error('Error get changed strategy parameters')
return [null, null, null]

const initParams = {}
initParams.paramRange = paramRange
Expand Down Expand Up @@ -168,7 +168,7 @@ action._getStrategyData = async () => {
ui.statusMessage('Get the initial parameters.')
const strategyData = await tv.getStrategy()
if(!strategyData || !strategyData.hasOwnProperty('name') || !strategyData.hasOwnProperty('properties') || !strategyData.properties) {
throw new Error('Could not find any strategy with parameters among the indicators. Add it to the chart and try again.')
throw new Error('The current strategy do not contain inputs, than can be optimized. You can choose another strategy to optimize.')
}
return strategyData
}
Expand Down
6 changes: 5 additions & 1 deletion content_scripts/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ model.getStrategyParameters = async (strategyData) => {
if(paramRange) {
const mismatched = Object.keys(paramRange).filter(key => !Object.keys(strategyData.properties).includes(key))
if(mismatched && mismatched.length) {
const isDef = confirm(`The data loaded from the storage has parameters that are not present in the current strategy: ${mismatched.join(',')}.\n\nYou need to load the correct strategy in the Tradingview chart or load new parameters for the current one. \nAlternatively, you can use the default strategy optimization parameters.\n\nShould it use the default settings?`)
// const isDef = confirm(`The data loaded from the storage has parameters that are not present in the current strategy: ${mismatched.join(',')}.\n\nYou need to load the correct strategy in the Tradingview chart or load new parameters for the current one. \nAlternatively, you can use the default strategy optimization parameters.\n\nShould it use the default settings?`)
const isDef = await ui.alertPopup (`The data loaded from the storage has parameters that are not present in the
current strategy: ${mismatched.join(',')}.\n\nYou need to load the correct strategy in the Tradingview chart or
load new parameters for the current one. \nAlternatively, you can use the default strategy optimization parameters.
\n\nShould it use the default settings?`, false, true)
if (!isDef)
return null
paramRange = model.getStrategyRange(strategyData)
Expand Down
21 changes: 20 additions & 1 deletion content_scripts/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const page = {}

page.waitForTimeout = async (timeout = 2500) => new Promise(resolve => setTimeout(resolve, timeout))

page.waitForSelector = async function (selector, timeout = 5000, isHide = false, parentEl) {
page.waitForSelectorOld2del = async function (selector, timeout = 5000, isHide = false, parentEl) { //2023-04-18
parentEl = parentEl ? parentEl : document
return new Promise(async (resolve) => {
let iter = 0
Expand All @@ -17,6 +17,25 @@ page.waitForSelector = async function (selector, timeout = 5000, isHide = false,
});
}


page.waitForSelector = async (selector, timeout = 5000, isHide = false, parentEl = null) => {
return new Promise(async (resolve) => {
parentEl = parentEl ? parentEl : document
let iter = 0
let elem = parentEl.querySelector(selector)
const tikTime = timeout === 0 ? 1000 : 50
while (timeout === 0 || (!isHide && !elem) || (isHide && !!elem)) {
await page.waitForTimeout(tikTime)
elem = parentEl.querySelector(selector)
iter += 1
if(timeout !== 0 && tikTime * iter >= timeout)
break
// throw new Error(`Timeout ${timeout} waiting for ${isHide ? 'hide ' : '' } ${selector}`) // break
}
return resolve(elem ? elem : null)
})
}

const reactValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
page._inputEvent = new Event('input', { bubbles: true});
page._changeEvent = new Event('change', { bubbles: true});
Expand Down
12 changes: 6 additions & 6 deletions content_scripts/selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ const SEL = {
tvLegendIndicatorItem: 'div[data-name="legend"] div[class^="sourcesWrapper"] div[class^="sources"] div[data-name="legend-source-item"]',
tvLegendIndicatorItemTitle: 'div[data-name="legend-source-title"]',
tvDialogRoot: '#overlap-manager-root',
indicatorTitle: '#overlap-manager-root div[data-name="indicator-properties-dialog"] div[class^="title"]',
tabInput: 'div[data-name="indicator-properties-dialog"] div[data-value="inputs"]',
tabInputActive: 'div[data-name="indicator-properties-dialog"] div[class*="active"][data-value="inputs"]',
tabProperties: 'div[data-name="indicator-properties-dialog"] div[data-value="properties"]',
indicatorTitle: '#overlap-manager-root div[data-name="indicator-properties-dialog"] [class^="container"] div[class^="title"]',
tabInput: '#overlap-manager-root div[data-name="indicator-properties-dialog"] [class^="tab"] button#inputs',
tabInputActive: '#overlap-manager-root div[data-name="indicator-properties-dialog"] [class^="tab"] button#inputs[class*="selected"]',
tabProperties: '#overlap-manager-root div[data-name="indicator-properties-dialog"] [class^="tab"] button#properties',
ticker: '#header-toolbar-symbol-search > div[class*="text-"]',
timeFrame: '#header-toolbar-intervals div[data-role^="button"]',
timeFrameActive: '#header-toolbar-intervals div[data-role^="button"][class*="isActive"]',
indicatorScroll: 'div[data-name="indicator-properties-dialog"] div[class^="scrollable-"]',
indicatorProperty: 'div[data-name="indicator-properties-dialog"] div[class^="content-"] div[class^="cell-"]',
okBtn: 'div[data-name="indicator-properties-dialog"] div[class^="footer-"] button[name="submit"]',
cancelBtn: 'div[data-name="indicator-properties-dialog"] span[data-name="close"][data-role="button"]',
strategyTesterTab: '#footer-chart-panel div[data-name="backtesting"]',
strategyTesterTabActive: '#footer-chart-panel div[data-name="backtesting"][data-active="true"]',
strategyTesterTab: '[data-name="backtesting"]', // 2023-10-19 #footer-chart-panel or #bottom-area
strategyTesterTabActive: '[data-name="backtesting"][data-active="true"]', // 2023-10-19 #footer-chart-panel or #bottom-area
strategyCaption: '#bottom-area div[class^="backtesting"] [class^="strategyGroup"] [data-strategy-title]',
strategyDialogParam: '#bottom-area div[class^="backtesting"] [class^="strategyGroup"] > div:nth-child(2) > button:nth-child(1)',
strategySummary: '#bottom-area div[class^="backtesting"] div[class^="tabSwitcher"] > button:nth-child(2)',
Expand Down
90 changes: 45 additions & 45 deletions content_scripts/tv.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,50 +36,37 @@ async function messageHandler(event) {
}


tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
let strategyData = {}
tv.getStrategy = async (strategyName = '', isIndicatorSave = false) => {
let indicatorName = null
if(strategyName !== null) {
if (!strategyName) {
let isStrategyActiveEl = document.querySelector(SEL.strategyTesterTabActive)
if(!isStrategyActiveEl) {
const strategyTabEl = document.querySelector(SEL.strategyTesterTab)
if(strategyTabEl) {
strategyTabEl.click()
} else {
await ui.showErrorPopup('There is not strategy tester tab on the page. Open correct page please')
return null
}
}
await tv.openStrategyTab()
let strategyCaptionEl = document.querySelector(SEL.strategyCaption)
// strategyCaptionEl = !strategyCaptionEl ? document.querySelector(SEL.strategyCaptionNew) : strategyCaptionEl // TODO 2del 22.05.31
if(!strategyCaptionEl || !strategyCaptionEl.innerText) {
await ui.showErrorPopup('There is not strategy name element on page. Open correct page please')
return null
throw new Error('There is not strategy name element on "Strategy tester" tab. Please retry. If the problem reproduced then it is possible taht TV UI changed. Check ' +
'<a href="https://github.com/akumidv/tradingview-assistant-chrome-extension/issues">issues</a>')
}
indicatorName = strategyCaptionEl.innerText

let stratParamEl = document.querySelector(SEL.strategyDialogParam)
if(!stratParamEl) {
await ui.showErrorPopup('There is not strategy param button on the strategy tab. Test stopped. Open correct page please')
return null
throw new Error('There is not strategy param button on the "Strategy tester" tab. Please retry. If the problem reproduced then it is possible taht TV UI changed. Check ' +
'<a href="https://github.com/akumidv/tradingview-assistant-chrome-extension/issues">issues</a>')
}
stratParamEl.click()
const dialogTitle = await page.waitForSelector(SEL.indicatorTitle, 2500)
if (!dialogTitle || !dialogTitle.innerText) {
await ui.showErrorPopup('There is open strategy properties. Open correct page please')
if (document.querySelector(SEL.cancelBtn))
document.querySelector(SEL.cancelBtn).click()
return null
throw new Error('The strategy parameter windows is not opened. Please retry. If the problem reproduced then it is possible taht TV UI changed. Check ' +
'<a href="https://github.com/akumidv/tradingview-assistant-chrome-extension/issues">issues</a>')
}

let isStrategyPropertiesTab = document.querySelector(SEL.tabProperties) // For strategy only
if (isIndicatorSave || isStrategyPropertiesTab) {
indicatorName = dialogTitle.innerText

}
}
else {
} else {
const indicatorLegendsEl = document.querySelectorAll(SEL.tvLegendIndicatorItem)
if(!indicatorLegendsEl)
return null
Expand All @@ -105,7 +92,6 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
}
}
}

} else {
let dialogTitleEl = await page.waitForSelector(SEL.indicatorTitle, 2500)
if (!dialogTitleEl || !dialogTitleEl.innerText) {
Expand All @@ -120,9 +106,29 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
}
}
if(indicatorName === null)
return strategyData
strategyData = {name: indicatorName, properties: {}}
if(await tv.changeDialogTabToInput()) {
throw new Error('It was not possible to find a strategy with parameters among the indicators. Add it to the chart and try again.')
// return strategyData

if(!await tv.changeDialogTabToInput())
throw new Error(`Can\'t activate input tab in strategy parameters`)
// if(await tv.changeDialogTabToInput()) {

// } else {
// console.error(`Can't set parameters tab to input`)
// }
const strategyInputs = await tv.getStrategyParams(isIndicatorSave)
const strategyData = {name: indicatorName, properties: strategyInputs}

if (document.querySelector(SEL.cancelBtn)) {
document.querySelector(SEL.cancelBtn).click()
await page.waitForSelector(SEL.cancelBtn, 1000, true)
}

return strategyData
}

tv.getStrategyParams = async (isIndicatorSave=false) => {
const strategyInputs = {} // TODO to list of values and set them in the same order
const indicProperties = document.querySelectorAll(SEL.indicatorProperty)
for (let i = 0; i < indicProperties.length; i++) {
const propClassName = indicProperties[i].getAttribute('class')
Expand All @@ -138,13 +144,13 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
let propValue = indicProperties[i].querySelector('input').value
if(indicProperties[i].querySelector('input').getAttribute('inputmode') === 'numeric' ||
(parseFloat(propValue) == propValue || parseInt(propValue) == propValue)) { // not only inputmode==numbers input have digits
const digPropValue = parseFloat(propValue) == parseInt(propValue) ? parseInt(propValue) : parseFloat(propValue) // TODO how to get float from param or just search point in string
const digPropValue = parseFloat(propValue) == parseInt(propValue) ? parseInt(propValue) : parseFloat(propValue) // Detection if float or int in the string
if(!isNaN(propValue))
strategyData.properties[propText] = digPropValue
strategyInputs[propText] = digPropValue
else
strategyData.properties[propText] = propValue
strategyInputs[propText] = propValue
} else {
strategyData.properties[propText] = propValue
strategyInputs[propText] = propValue
}
} else if(indicProperties[i].querySelector('span[role="button"]')) { // List
const buttonEl = indicProperties[i].querySelector('span[role="button"]')
Expand All @@ -153,7 +159,7 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
const propValue = buttonEl.innerText
if(propValue) {
if(isIndicatorSave) {
strategyData.properties[propText] = propValue
strategyInputs[propText] = propValue
continue
}
buttonEl.scrollIntoView()
Expand All @@ -169,10 +175,10 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
}
}
if(allOptionsList)
strategyData.properties[propText] = allOptionsList
strategyInputs[propText] = allOptionsList
page.mouseClick(buttonEl)
} else {
strategyData.properties[propText] = propValue
strategyInputs[propText] = propValue
}
}
} else { // Undefined
Expand All @@ -181,7 +187,7 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
} else if (propClassName.includes('fill-')) {
const element = indicProperties[i].querySelector('input[type="checkbox"]')
if(element)
strategyData.properties[propText] = element.getAttribute('checked') !== null ? element.checked : false
strategyInputs[propText] = element.getAttribute('checked') !== null ? element.checked : false
else { // Undefined type of element
continue
}
Expand All @@ -191,15 +197,7 @@ tv.getStrategy = async (strategyName = null, isIndicatorSave = false) => {
continue
}
}
} else {
console.error(`Can't set parameters tab to input`)
}
if (document.querySelector(SEL.cancelBtn)) {
document.querySelector(SEL.cancelBtn).click()
await page.waitForSelector(SEL.cancelBtn, 1000, true)
}

return strategyData
return strategyInputs
}

tv.setStrategyParams = async (name, propVal, isCheckOpenedWindow = false) => {
Expand Down Expand Up @@ -263,7 +261,7 @@ tv.changeDialogTabToInput = async () => {
if(isInputTabActive) return true
const inputTabEl = document.querySelector(SEL.tabInput)
if (!inputTabEl) {
throw new Error('There are no parameters in this strategy that can be optimized (There is no "Inputs" tab with parameters)')
throw new Error('There are no parameters in this strategy that can be optimized (There is no "Inputs" tab with input values)')
}
inputTabEl.click()
isInputTabActive = await page.waitForSelector(SEL.tabInputActive, 2000)
Expand Down Expand Up @@ -342,7 +340,9 @@ tv.openStrategyTab = async () => {
if(strategyTabEl) {
strategyTabEl.click()
} else {
throw new Error('There is not strategy tester tab on the page. Open correct page please')
throw new Error('There is not "Strategy Tester" tab on the page. Open correct page please or if it is ' +
'correct, then it is possible that TV UI changed. Create ' +
'<a href="https://github.com/akumidv/tradingview-assistant-chrome-extension/issues">issue</a>')
}
}
return true
Expand Down
8 changes: 4 additions & 4 deletions content_scripts/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ top:0px;
left:0px;
z-index:10000;`

async function alertPopup (msgText, isError = null, isConfirm = false) {
ui.alertPopup = async (msgText, isError = null, isConfirm = false) => {
return new Promise(resolve => {
function removeAlertPopup () {
const iondvAlertPopupEl = document.getElementById('iondvAlertPopup')
Expand Down Expand Up @@ -191,15 +191,15 @@ async function alertPopup (msgText, isError = null, isConfirm = false) {
}

ui.showPopup = async (msgText) => {
return await alertPopup(msgText, null)
return await ui.alertPopup(msgText, null)
}

ui.showErrorPopup = async (msgText) => {
return await alertPopup(msgText, true)
return await ui.alertPopup(msgText, true)
}

ui.showWarningPopup = async (msgText) => {
return await alertPopup(msgText, false)
return await ui.alertPopup(msgText, false)
}

ui.statusMessageRemove = () => {
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "An assistant for backtesting trading strategies and showing external signals in Tradingview",
"name": "Tradingview assistant",

"version": "2.3",
"version": "2.6",
"icons": {
"16": "images/tv_assist_16.png",
"32": "images/tv_assist_32.png",
Expand Down

0 comments on commit d444e40

Please sign in to comment.