diff --git a/.gitignore b/.gitignore index 6e11e51..049b951 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules/ out/ -*.db \ No newline at end of file +*.db +.DS_Store +.fleet/ \ No newline at end of file diff --git a/build.js b/build.js index e96899a..966330e 100644 --- a/build.js +++ b/build.js @@ -1,72 +1,29 @@ -const fs = require('fs'); -const { exec } = require('child_process'); -const path = require('path'); +const {exec} = require('child_process'); -const dbFolderPath = path.join(__dirname, 'db'); -const fileNames = ['account-settings.db']; // Add more file names as needed - -// Step one: Delete and recreate the files -function deleteAndRecreateFiles() { - return new Promise((resolve, reject) => { - const deletePromises = fileNames.map((fileName) => { - const filePath = path.join(dbFolderPath, fileName); - - return new Promise((resolve, reject) => { - fs.unlink(filePath, (err) => { - if (err && !fs.existsSync(filePath)) { - console.error('Error deleting file:', err); - reject(err); - return; - } - fs.writeFile(filePath, '', (err) => { - if (err) { - console.error('Error recreating file:', err); - reject(err); - return; - } - console.log('Recreated file:', filePath); - resolve(); - }); - }); - }); - }); - - Promise.all(deletePromises) - .then(() => { - resolve(); - }) - .catch((error) => { - reject(error); - }); - }); +const runBuildScript = () => { + return new Promise((resolve, reject) => { + exec('yarn run build', (error, stdout, stderr) => { + if (error) { + console.error(`Error executing 'yarn run build' command: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.error(`Command error: ${stderr}`); + reject(stderr); + return; + } + console.log(`Command output: ${stdout}`); + resolve(); + }); + }); } -// Step two: Run 'yarn run build' script -function runBuildScript() { - return new Promise((resolve, reject) => { - exec('yarn run build', (error, stdout, stderr) => { - if (error) { - console.error(`Error executing 'yarn run build' command: ${error.message}`); - reject(error); - return; - } - if (stderr) { - console.error(`Command error: ${stderr}`); - reject(stderr); - return; - } - console.log(`Command output: ${stdout}`); - resolve(); - }); - }); -} -// Execute the steps sequentially -deleteAndRecreateFiles() - .then(() => runBuildScript()) - .then(() => { - console.log('Build script completed successfully.'); - }) - .catch((error) => { - console.error('Error encountered:', error); - }); +runBuildScript() + .then(() => { + console.log('Build script completed successfully.'); + }) + .catch((error) => { + console.error('Error encountered:', error); + }); \ No newline at end of file diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..36f4efd --- /dev/null +++ b/client/index.html @@ -0,0 +1,86 @@ + + + + + + + + + Trader Bruh + + + + +
+ +
+
+ +
+

Trader Bruh - v3.0

+

by @PseudoCode88

+
+
+
+ +
+ +
+
+
+

Position Size (units)

+

0

+
+
+

Position Size (USD)

+

$0

+
+
+

Margin (USD)

+

$0.00

+
+
+
+ + +
+
+
+

Size Builder

+

Build your position size based on the stop loss and the risk you defined in + the account settings.

+
+ +
+
+ + +
+ +
+ + +
+
+ +
+
+ + +
+ +
+ + +
+
+
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/client/script.js b/client/script.js new file mode 100644 index 0000000..a5d86f7 --- /dev/null +++ b/client/script.js @@ -0,0 +1,110 @@ +const $ = require('jquery'); + +let PositionSizeBuilder = ($) => { + + let data = { + stopLoss: 0, + entryPrice: 0, + leverage: 1, + risk: 0, + direction: 'long', + positionSizeUnit: 0, + positionSizeUSD: 0, + margin: 0 + }; + + let el = { + textfield: { + stopLoss: $('#stop-loss'), + entryPrice: $('#entry-price'), + leverage: $('#leverage'), + riskAmount: $('#risk-amount') + }, + label: { + positionSizeUnit: $('#label-position-size-units'), + positionSizeUSD: $('#label-position-size-usd'), + margin: $('#label-margin-usd') + }, + wrapper: { + result: $('#result-panel') + } + } + + let eventBindings = () => { + Object.keys(el.textfield).forEach(function (id) { + el.textfield[id].on("keyup", updatePositionSize) + }) + } + + let getFormData = () => { + const formFields = { + stopLoss: el.textfield.stopLoss, + entryPrice: el.textfield.entryPrice, + leverage: el.textfield.leverage, + risk: el.textfield.riskAmount + }; + + return Object.entries(formFields).reduce((acc, [key, element]) => { + acc[key] = (element.val()) ? element.val() : '1'; + return acc; + }, {}); + } + + let updatePositionSize = () => { + const formData = getFormData(); + const data = calculatePositionSize(formData); + updateData(data); + render(); + } + + let updateData = (formData) => { + Object.keys(formData).forEach((key) => { + data[key] = formData[key]; + }) + } + + let calculatePositionSize = (data) => { + const { risk, entryPrice, stopLoss, leverage } = data; + + const priceDifference = (stopLoss > entryPrice) ? stopLoss - entryPrice : entryPrice - stopLoss; + + + if (priceDifference === 0) { + data.positionSizeUnit = 0; + data.positionSizeUSD = 0; + + } else { + data.positionSizeUnit = risk / Math.abs(priceDifference); + data.positionSizeUSD = (data.positionSizeUnit * entryPrice).toFixed(2); + } + + data.margin = ((data.positionSizeUnit * entryPrice) / leverage).toFixed(2); + data.direction = (stopLoss > entryPrice) ? 'short' : 'long' + + return data; + } + + let render = () => { + const elementsToUpdate = { + positionSizeUnit: Number(data.positionSizeUnit).toFixed(4), + positionSizeUSD: "$" + data.positionSizeUSD, + margin: "$" + data.margin + }; + + Object.entries(elementsToUpdate).forEach(([elementKey, value]) => { + el.label[elementKey].html(value); + }); + } + + let init = () => { + eventBindings(); + } + + return { + init: init + } +} + +document.addEventListener('DOMContentLoaded', () => { + PositionSizeBuilder($).init(); +}); \ No newline at end of file diff --git a/index.css b/client/style.css similarity index 53% rename from index.css rename to client/style.css index da6e6ac..53643f2 100644 --- a/index.css +++ b/client/style.css @@ -76,7 +76,7 @@ * { -webkit-font-smoothing: antialiased; - font-family: "Plus Jakarta Sans", system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + font-family: "Manrope", system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { @@ -93,18 +93,29 @@ p { margin: 0; } +h1 { + font-size: 32px; + letter-spacing: -0.02em; + margin: 0px 0 32px 0; +} + +h2 { + font-size: 18px; + letter-spacing: -0.02em; +} + main { - max-width: 520px; - padding: 32px; + max-width: 400px; + padding: 32px 0 0 0; margin: auto; box-sizing: border-box; position: relative; } section { - background-color: var(--static-surface-secondary); - padding: 24px; - border-radius: 16px; + /* background-color: var(--static-surface-secondary); + padding: 24px; */ + border-radius: 24px; } label { @@ -133,24 +144,6 @@ input[type=number]:focus { border: 1px solid var(--int-border-focus); } -/** status **/ - -.clr-info { - color: var(--content-info) !important; -} - -.clr-success { - color: var(--content-success) !important; -} - -.clr-warning { - color: var(--content-warning) !important; -} - -.clr-danger { - color: var(--content-danger) !important; -} - /** Flex layouts **/ .fr { @@ -199,6 +192,24 @@ input[type=number]:focus { border-radius: 10px; } +.Credits { + padding: 0 32px; +} + +.Credits-Title { + font-size: 14px; + font-weight: 900; + color: var(--content-primary); + margin-bottom: 2px; +} + +.Credits-Creator { + font-size: 10px; + font-weight: 600; + color: var(--content-muted); +} + + .Section h2 { margin: 0; font-size: 18px; @@ -218,264 +229,35 @@ input[type=number]:focus { margin: 0; } -.BestPostion { - font-size: 15px; - font-weight: 600; - line-height: 1.6; - color: var(--content-secondary); -} - -.RList { - width: 100%; -} - -.RList-Title { - width: 100%; - justify-content: space-between; - border-bottom: 1px solid var(--static-border-primary); - padding: 10px 0; -} - -.RList-Title p { - width: 16%; - font-size: 12px; - font-weight: 500; -} - -.RList-Item { - width: 100%; - justify-content: space-between; - border-bottom: 1px solid var(--static-border-primary); - padding: 10px 0; -} - -.RList-Item-low { - background-color: var(--int-support-info-secondary-default); -} - -.RList-Item:last-child { - border-bottom: 0; -} - -.RList-Item p { - width: 16%; - font-size: 12px; - color: var(--content-primary); - font-weight: 500; -} - -.RList-Label-right { - text-align: right; -} - -.Size { - width: 100%; - display: flex; - width: 100%; - gap: 20px; - flex-direction: column; -} - -.Settings { - width: 100%; - display: flex; - width: 100%; - gap: 20px; -} - -.Settings__Capital { - flex-grow: 1; -} - -.Settings__Risk { - width: 20%; -} - -.Settings__Risk-Min, -.Settings__Risk-Min { - width: 50%; -} - -h1 { - font-size: 32px; - letter-spacing: -0.02em; - margin: 0px 0 32px 0; -} - -.sub-label { +.Heading-Subtitle { font-size: 14px; font-weight: 400; + line-height: 1.45; color: #808080; - margin-bottom: 4px; display: block; margin: 0 0 8px 0; } -hr { - border: 0; - border-top: 1px solid var(--static-border-primary); - margin: 8px 0; -} - -input[type=range] { - width: 100%; - margin-top: 12px; +.Wrapper-Position-Size-Result { + padding: 32px; + padding-bottom: 120px; + background-color: #878aff; } -.Value p { - font-size: 18px; +.Wrapper-Position-Size-Result .label { font-weight: 700; - margin: 16px 0; -} - -.InlineFlag { - padding: 16px; - background-color: var(--int-support-warning-secondary-default); - border-radius: 8px; -} - -.InlineFlag p { - font-size: 14px; - font-weight: 500; -} - -/** Button **/ -button { - border-radius: 100px; - border: 0; - padding: 10px 16px; - font-size: 14px; - font-weight: 600; - cursor: pointer; -} - -.Button-Primary { - background-color: var(--int-surface-brand-primary-default); - color: var(--content-on-brand); -} - -.Button-Primary:hover { - background-color: var(--int-surface-brand-primary-hover); -} - -.Button-Primary:active { - background-color: var(--int-surface-brand-primary-active); -} - -.Button-Secondary { - background-color: var(--int-surface-brand-secondary-default); - color: var(--content-on-brand); -} - -.Button-Secondary:hover { - background-color: var(--int-surface-brand-secondary-hover); -} - -.Button-Secondary:active { - background-color: var(--int-surface-brand-secondary-active); -} - -/** Account Setting **/ - -.AccountSettingsList-Item { - width: 100%; - justify-content: space-between; - border-bottom: 1px solid var(--static-border-primary); - padding: 10px 0; -} - -.AccountSettingsList-Item:first-child { - padding-top: 0; -} - -.AccountSettingsList-Item:last-child { - border-bottom: 0; -} - -.AccountSettingsList-Item p { - width: 50%; - font-size: 14px; - color: var(--content-secondary); - font-weight: 500; -} - -.FormAccountSettings-ButtonGroup { - width: 100%; -} - -.FormAccountSettings-ButtonGroup button:first-child { - width: 70%; -} - -.PositionSize { - width: 100%; - padding: 0; - border-radius: 16px; - box-sizing: border-box; -} - -.PositionSize-Item { - padding: 12px 0; - width: 100%; - border-bottom: 1px solid var(--static-border-primary); -} - -.PositionSize-Item:first-child { - padding-top: 0; -} - -.PositionSize-Item:last-child { - border: 0; -} - -.PositionSize-Item p { - font-size: 14px; - font-weight: 600; -} - -.PositionSize-Item-Label { - width: 100%; - color: var(--content-primary); - margin: 0; -} - -.PositionSize-Item-Value { - width: 100%; - color: var(--content-secondary); - margin: 0; - text-align: right; -} - -.Credits { - width: 100%; - opacity: 0.5; -} - -.Credits-Title { - font-size: 14px; - font-weight: 900; - color: var(--content-muted); - margin-bottom: 2px; -} - -.Credits-Creator { - font-size: 10px; - font-weight: 500; - color: var(--content-muted); -} - -.Welcome { - background-color: var(--int-support-info-primary-default); - display: none; + font-size: 12px; + color: #000; } -.Welcome p { - font-size: 16px; - font-weight: 600; - line-height: 1.45; - color: var(--content-secondary); +.Wrapper-Position-Size-Result .value { + font-weight: 400; + font-size: 32px; + color: #000; } -.Welcome span { - color: var(--content-warning) +.Wrapper-Position-Size-Form { + background-color: var(--static-surface-secondary); + padding: 32px; + margin-top: -88px; } \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index eaacc4d..0000000 --- a/index.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - Trader Bruh - - - - -
- - -
-

Setup your trading account parameters to use the position size builder. Scroll to the bottom - to see the account settings.

-
- -
-
-
-

Position Size Builder

-

Build your position size based on the stop loss and the risk you defined in the account - settings.

-
- -
-
-

Capital at Risk

-

0

-
-
-

Potential Gain

-

0

-
-
-

Margin

-

0

-
-
- -
-
- - -
- -
- - -
- -
- - -
-
- -
- - -
- -
- -
-
-

Position Size Suggestion

-

Position size range based on your risk
Stop Loss -  →  -

-

Below is a list of different position sizes calculated based on your risk per trade

-
-
-

Risk

-

Size

-

Loss

-

Gain

-

Lev

-

Margin

-
-
-

Low

-

0

-

0

-

0

-

0

-

0

-
-
-

Medium

-

0

-

0

-

0

-

0

-

0

-
-
-

High

-

0

-

0

-

0

-

0

-

0

-
-
-

x High

-

0

-

0

-

0

-

0

-

0

-
-
-
- -
- -
-
-
-

Account Settings

-

To setup your trading account, add the capital, risk per trade and the exchange maker and - taker fee. This is important to fill first to simulate the position size.

-
- -
- -
-
-

Trading Capital

-

-

-
-
-

Risk per Trade - Min%

-

-

-
-
-

Risk per Trade - Max%

-

-

-
-
-

Maker Fee

-

-

-
-
-

Taker Fee

-

-

-
-
- - -
- -
-
- - -
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- -
- - -
-
- -
-
- -
-

Trader Bruh - v1.1

-

by @PseudoCode88

-
-
- - - - - - - - - - \ No newline at end of file diff --git a/index.js b/index.js index 6464f7d..2776566 100644 --- a/index.js +++ b/index.js @@ -1,34 +1,34 @@ -const { app, BrowserWindow } = require('electron'); +const {app, BrowserWindow} = require('electron'); const createWindow = () => { - const win = new BrowserWindow({ - width: 480, - minWidth: 480, - height: 1000, - minHeight: 640, - webPreferences: { - nodeIntegration: true, - contextIsolation: false - }, - icon: 'assets/logo-1000.png', - }) + const win = new BrowserWindow({ + width: 400, + minWidth: 400, + height: 752, + minHeight: 752, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + }, + icon: 'assets/logo-1000.png', + }) - win.resizable = true; - win.setAlwaysOnTop(true); + win.resizable = true; + win.setAlwaysOnTop(true); - win.loadFile('index.html') + win.loadFile('client/index.html') } app.setName("Trader Bruh"); app.whenReady().then(() => { - createWindow() + createWindow() - app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) createWindow() - }) + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) app.on('window-all-closed', () => { - if (process.platform !== 'darwin') app.quit() + if (process.platform !== 'darwin') app.quit() }) \ No newline at end of file diff --git a/package.json b/package.json index 5a3aedf..521e8b6 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "trader-bruh", - "version": "1.1", + "version": "3.0", "description": "Position Size Calculator", "main": "index.js", "keywords": [ + "trade", "position size", - "crypto" + "calculator" ], "scripts": { "start": "electron .", @@ -14,6 +15,9 @@ }, "author": "pseudocode88", "license": "ISC", + "dependencies": { + "jquery": "^3.7.0" + }, "devDependencies": { "@electron-forge/cli": "^6.2.1", "@electron-forge/maker-dmg": "^6.2.1", @@ -34,11 +38,15 @@ "icon": "assets/logo.icns", "name": "Trader Bruh", "iconSize": "10" - } + }, + "ignore": [ + ".gitignore", + "package.json", + "build.js", + "README.md", + "yarn.lock", + ".fleet/" + ] } - }, - "dependencies": { - "jquery": "^3.7.0", - "nedb": "^1.8.0" } } \ No newline at end of file diff --git a/scripts/account-settings.js b/scripts/account-settings.js deleted file mode 100644 index 0637cc0..0000000 --- a/scripts/account-settings.js +++ /dev/null @@ -1,136 +0,0 @@ -var AccountSettings = ($, db) => { - - var data = { - exchange: 'default', - capital: 0, - minRisk: 0, - minRiskAmt: 0, - maxRisk: 0, - maxRiskAmt: 0, - makerFee: 0, - takerFee: 0 - }; - - var el = { - txtCapital: $('#txt-capital'), - txtMinRisk: $('#txt-min-risk'), - txtMaxRisk: $('#txt-max-risk'), - txtMakerFee: $('#txt-maker-fee'), - txtTakerFee: $('#txt-taker-fee'), - lblCapital: $('#lbl-capital'), - lblMinRisk: $('#lbl-min-risk'), - lblMaxRisk: $('#lbl-max-risk'), - lblMakerFee: $('#lbl-maker-fee'), - lblTakerFee: $('#lbl-taker-fee'), - btnEdit: $('#button-edit-account-settings'), - btnCancel: $('#button-cancel-account-settings'), - btnSave: $('#button-save-account-settings'), - divForm: $('#form-account-settings'), - divSection: $('#section-account-settings') - } - - var eventBindings = () => { - el.btnEdit.on("click", () => { toggleSection(true) }); - el.btnCancel.on("click", () => { toggleSection(false) }); - el.btnSave.on("click", () => { - updateLocalData(getFormData()); - updateDB(); - toggleSection(false); - }); - } - - function toggleSection(showForm) { - render(showForm); - - if (showForm) { - el.divForm.removeClass('hide'); - el.divSection.addClass('hide'); - } else { - el.divForm.addClass('hide'); - el.divSection.removeClass('hide'); - } - } - - var getFormData = () => { - var formData = { - exchange: 'default', - capital: parseFloat(el.txtCapital.val()), - minRisk: parseFloat(el.txtMinRisk.val()), - maxRisk: parseFloat(el.txtMaxRisk.val()), - makerFee: parseFloat(el.txtMakerFee.val()), - takerFee: parseFloat(el.txtTakerFee.val()), - minRiskAmt: 0, - maxRiskAmt: 0 - }; - - formData.minRiskAmt = parseFloat(formData.capital * (formData.minRisk / 100)); - formData.maxRiskAmt = parseFloat(formData.capital * (formData.maxRisk / 100)); - - return formData; - } - - var updateDB = () => { - var that = this; - db.findOne({ exchange: 'default' }, (err, docs) => { - if (!docs) { - db.insert(data); - that.observer.fire('AccountSettingsLoaded'); - } else { - db.update({ exchange: 'default' }, data); - that.observer.fire('AccountSettingsLoaded'); - } - }) - } - - var updateLocalData = (docs) => { - data.exchange = docs.exchange; - data.capital = parseFloat(docs.capital); - data.minRisk = parseFloat(docs.minRisk); - data.minRiskAmt = parseFloat(docs.minRiskAmt); - data.maxRisk = parseFloat(docs.maxRisk); - data.maxRiskAmt = parseFloat(docs.maxRiskAmt); - data.makerFee = parseFloat(docs.makerFee); - data.takerFee = parseFloat(docs.takerFee); - } - - var render = (isForm) => { - if (isForm) { - el.txtCapital.val(data.capital); - el.txtMinRisk.val(data.minRisk); - el.txtMaxRisk.val(data.maxRisk); - el.txtMakerFee.val(data.makerFee); - el.txtTakerFee.val(data.takerFee); - } else { - el.lblCapital.html(data.capital); - el.lblMinRisk.html(data.minRisk + '%'); - el.lblMaxRisk.html(data.maxRisk + '%'); - el.lblMakerFee.html(data.makerFee + '%'); - el.lblTakerFee.html(data.takerFee + '%'); - } - } - - var getData = () => { - return data; - } - - var init = () => { - eventBindings(); - var that = this; - - db.findOne({ exchange: 'default' }, (err, docs) => { - if (docs) { - updateLocalData(docs); - that.observer.fire('AccountSettingsLoaded'); - } else { - that.observer.fire('AccountSettingsNotFound'); - } - render(); - }) - } - - return { - init: init, - getData: getData - }; - -}; \ No newline at end of file diff --git a/scripts/deps.js b/scripts/deps.js deleted file mode 100644 index 3ef233e..0000000 --- a/scripts/deps.js +++ /dev/null @@ -1,2 +0,0 @@ -const $ = require('jquery'); -const DS = require('nedb'); \ No newline at end of file diff --git a/scripts/index.js b/scripts/index.js deleted file mode 100644 index 0979880..0000000 --- a/scripts/index.js +++ /dev/null @@ -1,29 +0,0 @@ -var db = {}; - -$(window).on('load', () => { - db.accountSettings = new DS({ - filename: __dirname + '/db/account-settings.db', - autoload: true, - timestampData: true - }); - - this.observer = Observer; - - this.modules = { - AccountSettings: AccountSettings($, db.accountSettings), - PositionSizeBuilder: PositionSizeBuilder($), - PositionSizeSuggestion: PositionSizeSuggestion($) - } - - this.modules.AccountSettings.init(); - this.modules.PositionSizeBuilder.init(); - - this.observer.on('PositionSizeCalculated', this.modules.PositionSizeSuggestion.render); - this.observer.on('AccountSettingsLoaded', this.modules.PositionSizeBuilder.sync); - this.observer.on('AccountSettingsNotFound', () => { - $('#welcome-flag').show(); - }); - this.observer.on('AccountSettingsLoaded', () => { - $('#welcome-flag').hide(); - }); -}) \ No newline at end of file diff --git a/scripts/observer.js b/scripts/observer.js deleted file mode 100644 index ecf75be..0000000 --- a/scripts/observer.js +++ /dev/null @@ -1,27 +0,0 @@ -var Observer = { - - subscribers: {}, - - fire: function (eventName) { - if (this.subscribers.hasOwnProperty(eventName)) { - var e = this.subscribers[eventName], - args = null; - if (arguments.length > 1) { - args = Array.prototype.slice.call(arguments, 1); - } - - for (var i = 0; i < e.length; i++) { - e[i].apply(this, args); - } - } - }, - - on: function (eventName, callback) { - if (!this.subscribers.hasOwnProperty(eventName)) { - this.subscribers[eventName] = []; - } - - this.subscribers[eventName].push(callback); - } - -}; \ No newline at end of file diff --git a/scripts/position-size-builder.js b/scripts/position-size-builder.js deleted file mode 100644 index 4e07e27..0000000 --- a/scripts/position-size-builder.js +++ /dev/null @@ -1,94 +0,0 @@ -var PositionSizeBuilder = ($) => { - - var data = { - stopLoss: 0, - takeProfit: 0, - leverage: 1, - positionSize: 0, - margin: 0, - risk: 0, - gain: 0 - }; - - var el = { - txtStopLoss: $('#txt-sl'), - txtTakeProfit: $('#txt-tp'), - txtLeverage: $('#txt-lev'), - txtPositionSize: $('#txt-ps'), - lblRisk: $('#lbl-risk'), - lblGain: $('#lbl-gain'), - lblMargin: $('#lbl-margin') - } - - var eventBindings = () => { - el.txtStopLoss.on("keyup", updatePositionSize); - el.txtTakeProfit.on("keyup", updatePositionSize); - el.txtLeverage.on("keyup", updatePositionSize); - el.txtPositionSize.on("keyup", updatePositionSize); - } - - var getFormData = () => { - return { - stopLoss: el.txtStopLoss.val() || 1, - takeProfit: el.txtTakeProfit.val() || 1, - leverage: el.txtLeverage.val() || 1, - positionSize: el.txtPositionSize.val() - } - } - - var updatePositionSize = () => { - updateLocalData(getFormData()); - calculatePositionSize(); - render(); - this.observer.fire('PositionSizeCalculated') - } - - var updateLocalData = (formData) => { - Object.keys(formData).forEach((key) => { - data[key] = formData[key]; - }) - } - - var calculatePositionSize = () => { - data.margin = data.positionSize / data.leverage; - data.margin = data.margin.toFixed(2); - - data.risk = ((data.stopLoss / 100) * data.leverage) * data.margin - data.risk = data.risk.toFixed(2); - - data.gain = ((data.takeProfit / 100) * data.leverage) * data.margin - data.gain = data.gain.toFixed(2); - - return data; - } - - var render = () => { - el.lblRisk.html(data.risk); - el.lblGain.html(data.gain); - el.lblMargin.html(data.margin); - - var accountSettingsData = this.modules.AccountSettings.getData(); - - if (data.risk < accountSettingsData.minRiskAmt) { - el.lblRisk.removeClass('clr-warning clr-danger').addClass('clr-success'); - } else if (data.risk > accountSettingsData.minRiskAmt && data.risk < accountSettingsData.maxRiskAmt) { - el.lblRisk.removeClass('clr-danger clr-success').addClass('clr-warning'); - } else { - el.lblRisk.removeClass('clr-success clr-warning').addClass('clr-danger'); - } - } - - var getData = () => { - return data; - } - - var init = () => { - eventBindings(); - } - - return { - init: init, - getData: getData, - sync: updatePositionSize, - } -} \ No newline at end of file diff --git a/scripts/position-size-suggestion.js b/scripts/position-size-suggestion.js deleted file mode 100644 index 0aa06ac..0000000 --- a/scripts/position-size-suggestion.js +++ /dev/null @@ -1,71 +0,0 @@ -var PositionSizeSuggestion = ($) => { - var renderSuggestion = () => { - var accountSettingsData = this.modules.AccountSettings.getData(), - positionSizeData = this.modules.PositionSizeBuilder.getData(), - riskLevels = {}, - suggestions = []; - - riskLevels = getRiskLevels(accountSettingsData); - suggestions = calculateSuggestions(riskLevels, positionSizeData); - render(suggestions, positionSizeData); 10 - } - - var calculateSuggestions = (riskLevels, positionSizeData) => { - var risk = 0, - margin = 0, - leverage = 1, - positionSize = 0, - gain = 0, - stopLoss = positionSizeData.stopLoss / 100, - takeProfit = positionSizeData.takeProfit / 100, - id = '', - suggestions = []; - - return Object.keys(riskLevels).map((key) => { - id = key; - risk = riskLevels[key]; - margin = risk + 1; - leverage = Math.floor(risk / (margin * stopLoss)); - positionSize = Math.floor(margin * leverage); - gain = Math.floor(positionSize * takeProfit); - - return { - id: id, - risk: risk, - margin: margin, - leverage: leverage, - gain: gain, - positionSize: positionSize - }; - }); - } - - var render = (suggestions, positionSizeData) => { - var prefix = ''; - - suggestions.forEach((item) => { - prefix = '#' + item.id + '-' - $(prefix + "size").html(item.positionSize); - $(prefix + "loss").html(item.risk); - $(prefix + "gain").html(item.gain); - $(prefix + "lev").html(item.leverage); - $(prefix + "margin").html(item.margin); - }) - - $('#best-position').html(suggestions[0].positionSize + '-' + suggestions[3].positionSize); - $('#best-stop-loss').html(positionSizeData.stopLoss + '%'); - } - - var getRiskLevels = (data) => { - return { - l: Math.floor(data.capital * ((data.minRisk - 1) / 100)), - m: Math.floor(data.capital * (data.minRisk / 100)), - h: Math.floor(data.capital * (((parseFloat(data.minRisk) + parseFloat(data.maxRisk)) / 2) / 100)), - xh: Math.floor(data.capital * (data.maxRisk / 100)) - } - } - - return { - render: renderSuggestion - } -} \ No newline at end of file