From ad18cd3fb7c28f6cc5d083fa8182077acfde89f4 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Wed, 12 Jul 2023 12:59:56 +0700 Subject: [PATCH 01/10] Update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6e11e51..ca6d9c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ out/ -*.db \ No newline at end of file +*.db +.DS_Store \ No newline at end of file From 581937c7e4e41019023105237073526492d81721 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Fri, 26 Jul 2024 18:56:42 +0700 Subject: [PATCH 02/10] Replace new formula for calculating position --- index.html | 50 ++++++++++++++++++------------ scripts/position-size-builder.js | 52 +++++++++++++++++--------------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/index.html b/index.html index eaacc4d..f121c0b 100644 --- a/index.html +++ b/index.html @@ -27,30 +27,22 @@

Position Size Builder

settings.

-
-
-

Capital at Risk

-

0

-
-
-

Potential Gain

-

0

-
-
-

Margin

-

0

+
+
+ +
-
-
- +
+
+
- - + +
@@ -59,10 +51,30 @@

Position Size Builder

-
+
+
+

Position Size

+

0

+
+ +
+

Margin

+

0

+
+
+ + + diff --git a/scripts/position-size-builder.js b/scripts/position-size-builder.js index 4e07e27..4cdc7f6 100644 --- a/scripts/position-size-builder.js +++ b/scripts/position-size-builder.js @@ -2,37 +2,35 @@ var PositionSizeBuilder = ($) => { var data = { stopLoss: 0, - takeProfit: 0, + entryPoint: 0, leverage: 1, positionSize: 0, margin: 0, risk: 0, - gain: 0 }; var el = { txtStopLoss: $('#txt-sl'), - txtTakeProfit: $('#txt-tp'), + txtEntryPoint: $('#txt-ep'), txtLeverage: $('#txt-lev'), - txtPositionSize: $('#txt-ps'), - lblRisk: $('#lbl-risk'), - lblGain: $('#lbl-gain'), + txtRiskAmount: $('#txt-risk'), + lblPositionSize: $('#lbl-ps'), lblMargin: $('#lbl-margin') } var eventBindings = () => { el.txtStopLoss.on("keyup", updatePositionSize); - el.txtTakeProfit.on("keyup", updatePositionSize); + el.txtEntryPoint.on("keyup", updatePositionSize); el.txtLeverage.on("keyup", updatePositionSize); - el.txtPositionSize.on("keyup", updatePositionSize); + el.txtRiskAmount.on("keyup", updatePositionSize); } var getFormData = () => { return { stopLoss: el.txtStopLoss.val() || 1, - takeProfit: el.txtTakeProfit.val() || 1, + entryPoint: el.txtEntryPoint.val() || 1, leverage: el.txtLeverage.val() || 1, - positionSize: el.txtPositionSize.val() + risk: el.txtRiskAmount.val() || 1 } } @@ -49,33 +47,39 @@ var PositionSizeBuilder = ($) => { }) } + // unit = risk /(ep - sl) + // margin = (unit * ep)/lev + var calculatePositionSize = () => { - data.margin = data.positionSize / data.leverage; + data.positionSize = Math.round(data.risk / (data.entryPoint - data.stopLoss)); + + data.margin = (data.positionSize * data.entryPoint) / data.leverage; data.margin = data.margin.toFixed(2); - data.risk = ((data.stopLoss / 100) * data.leverage) * data.margin - data.risk = data.risk.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); + // 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.lblRisk.html(data.risk); + // el.lblGain.html(data.gain); el.lblMargin.html(data.margin); + el.lblPositionSize.html(data.positionSize); 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'); - } + // 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 = () => { From 1bb3c8e662273791ce25c5e2f9642739820384b7 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Tue, 3 Sep 2024 18:18:04 +0700 Subject: [PATCH 03/10] Remove all complexity and keep the app focused on position size calculation --- index.css | 323 +++++----------------------- index.html | 215 ++++-------------- index.js | 8 +- scripts/account-settings.js | 136 ------------ scripts/deps.js | 3 +- scripts/index.js | 36 +--- scripts/observer.js | 27 --- scripts/position-size-builder.js | 111 +++++----- scripts/position-size-suggestion.js | 71 ------ 9 files changed, 164 insertions(+), 766 deletions(-) delete mode 100644 scripts/account-settings.js delete mode 100644 scripts/observer.js delete mode 100644 scripts/position-size-suggestion.js diff --git a/index.css b/index.css index da6e6ac..740ed26 100644 --- a/index.css +++ b/index.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,25 @@ input[type=number]:focus { border-radius: 10px; } +.Credits { + width: 100%; + 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 +230,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 index f121c0b..09271c6 100644 --- a/index.html +++ b/index.html @@ -12,210 +12,77 @@
- -
-

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.

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

Position Size

-

0

-
- -
-

Margin

-

0

-
+
+
+ +
+

Trader Bruh - v3.0

+

by @PseudoCode88

+
+
- - - -
- -
-
-

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

+
+ +
+
+
+

Position Size (units)

+

0

-
-

Medium

-

0

-

0

-

0

-

0

-

0

+
+

Position Size (USD)

+

$0

-
-

High

-

0

-

0

-

0

-

0

-

0

-
-
-

x High

-

0

-

0

-

0

-

0

-

0

+
+

Margin (USD)

+

$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

-

-

-
-
- - -
- -
-
- - + +
+
+
+

Size Builder

+

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

- - + +
+
- - + +
- - + +
+
- - + +
- -
- - -
- -
+
-
-

Trader Bruh - v1.1

-

by @PseudoCode88

-
+
- - - diff --git a/index.js b/index.js index 6464f7d..aca1b3c 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,10 @@ const { app, BrowserWindow } = require('electron'); const createWindow = () => { const win = new BrowserWindow({ - width: 480, - minWidth: 480, - height: 1000, - minHeight: 640, + width: 400, + minWidth: 400, + height: 752, + minHeight: 752, webPreferences: { nodeIntegration: true, contextIsolation: false 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 index 3ef233e..4af07bf 100644 --- a/scripts/deps.js +++ b/scripts/deps.js @@ -1,2 +1 @@ -const $ = require('jquery'); -const DS = require('nedb'); \ No newline at end of file +const $ = require('jquery'); \ No newline at end of file diff --git a/scripts/index.js b/scripts/index.js index 0979880..4a6c68a 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -1,29 +1,13 @@ var db = {}; -$(window).on('load', () => { - db.accountSettings = new DS({ - filename: __dirname + '/db/account-settings.db', - autoload: true, - timestampData: true +document.addEventListener('DOMContentLoaded', () => { + const modules = { + PositionSizeBuilder: PositionSizeBuilder($) + }; + + Object.values(modules).forEach(module => { + if (typeof module.init === 'function') { + module.init(); + } }); - - 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 +}); \ 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 index 4cdc7f6..e196ae2 100644 --- a/scripts/position-size-builder.js +++ b/scripts/position-size-builder.js @@ -2,88 +2,89 @@ var PositionSizeBuilder = ($) => { var data = { stopLoss: 0, - entryPoint: 0, + entryPrice: 0, leverage: 1, - positionSize: 0, - margin: 0, risk: 0, + direction: 'long', + positionSizeUnit: 0, + positionSizeUSD: 0, + margin: 0 }; var el = { - txtStopLoss: $('#txt-sl'), - txtEntryPoint: $('#txt-ep'), - txtLeverage: $('#txt-lev'), - txtRiskAmount: $('#txt-risk'), - lblPositionSize: $('#lbl-ps'), - lblMargin: $('#lbl-margin') + 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') + } } var eventBindings = () => { - el.txtStopLoss.on("keyup", updatePositionSize); - el.txtEntryPoint.on("keyup", updatePositionSize); - el.txtLeverage.on("keyup", updatePositionSize); - el.txtRiskAmount.on("keyup", updatePositionSize); + Object.keys(el.textfield).forEach(function (id) { + el.textfield[id].on("keyup", updatePositionSize) + }) } var getFormData = () => { - return { - stopLoss: el.txtStopLoss.val() || 1, - entryPoint: el.txtEntryPoint.val() || 1, - leverage: el.txtLeverage.val() || 1, - risk: el.txtRiskAmount.val() || 1 - } + 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() || '1'; + return acc; + }, {}); } var updatePositionSize = () => { - updateLocalData(getFormData()); - calculatePositionSize(); + const formData = getFormData(); + const data = calculatePositionSize(formData); + console.log(data); + updateData(data); render(); - this.observer.fire('PositionSizeCalculated') } - var updateLocalData = (formData) => { + var updateData = (formData) => { Object.keys(formData).forEach((key) => { data[key] = formData[key]; }) } - // unit = risk /(ep - sl) - // margin = (unit * ep)/lev - - var calculatePositionSize = () => { - data.positionSize = Math.round(data.risk / (data.entryPoint - data.stopLoss)); - - data.margin = (data.positionSize * data.entryPoint) / data.leverage; - data.margin = data.margin.toFixed(2); + var calculatePositionSize = (data) => { + const { risk, entryPrice, stopLoss, leverage } = data; - // data.risk = ((data.stopLoss / 100) * data.leverage) * data.margin - // data.risk = data.risk.toFixed(2); + const priceDifference = (stopLoss > entryPrice) ? stopLoss - entryPrice : entryPrice - stopLoss; - // data.gain = ((data.takeProfit / 100) * data.leverage) * data.margin - // data.gain = data.gain.toFixed(2); + data.positionSizeUnit = Math.round(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; } var render = () => { - // el.lblRisk.html(data.risk); - // el.lblGain.html(data.gain); - el.lblMargin.html(data.margin); - el.lblPositionSize.html(data.positionSize); - - 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; + const elementsToUpdate = { + positionSizeUnit: data.positionSizeUnit, + positionSizeUSD: "$" + data.positionSizeUSD, + margin: "$" + data.margin + }; + + Object.entries(elementsToUpdate).forEach(([elementKey, value]) => { + el.label[elementKey].html(value); + }); } var init = () => { @@ -91,8 +92,6 @@ var PositionSizeBuilder = ($) => { } return { - init: init, - getData: getData, - sync: updatePositionSize, + init: init } } \ 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 From 71cefff84b17d5f5517dff7ca930e627bb63e479 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Tue, 3 Sep 2024 18:25:38 +0700 Subject: [PATCH 04/10] Update package and build file --- build.js | 2 +- package.json | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/build.js b/build.js index e96899a..e8e9e4c 100644 --- a/build.js +++ b/build.js @@ -3,7 +3,7 @@ const { exec } = require('child_process'); const path = require('path'); const dbFolderPath = path.join(__dirname, 'db'); -const fileNames = ['account-settings.db']; // Add more file names as needed +const fileNames = []; // Add more file names as needed // Step one: Delete and recreate the files function deleteAndRecreateFiles() { diff --git a/package.json b/package.json index 5a3aedf..ddda603 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "trader-bruh", - "version": "1.1", + "version": "3.0", "description": "Position Size Calculator", "main": "index.js", "keywords": [ @@ -38,7 +38,6 @@ } }, "dependencies": { - "jquery": "^3.7.0", - "nedb": "^1.8.0" + "jquery": "^3.7.0" } } \ No newline at end of file From 4832fbe91a5d0e299f35c61757bddc33125e23e3 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Wed, 4 Sep 2024 00:49:13 +0700 Subject: [PATCH 05/10] Fix css issue --- index.css | 1 - 1 file changed, 1 deletion(-) diff --git a/index.css b/index.css index 740ed26..53643f2 100644 --- a/index.css +++ b/index.css @@ -193,7 +193,6 @@ input[type=number]:focus { } .Credits { - width: 100%; padding: 0 32px; } From 6783a7e06b8d5693941f2bbc71cf48e566b52dd4 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Thu, 12 Sep 2024 17:37:14 +0700 Subject: [PATCH 06/10] Add fleet config to git ignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ca6d9c4..049b951 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/ out/ *.db -.DS_Store \ No newline at end of file +.DS_Store +.fleet/ \ No newline at end of file From 0b1485b6706cc920328d3fa33aaca8fa4c935dfe Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Thu, 12 Sep 2024 17:37:54 +0700 Subject: [PATCH 07/10] Conslidated multiple js file and css to client folder --- client/index.html | 86 ++++++++++++++++++++++++ client/script.js | 110 +++++++++++++++++++++++++++++++ index.css => client/style.css | 0 index.html | 89 ------------------------- index.js | 40 +++++------ scripts/deps.js | 1 - scripts/index.js | 13 ---- scripts/position-size-builder.js | 97 --------------------------- 8 files changed, 216 insertions(+), 220 deletions(-) create mode 100644 client/index.html create mode 100644 client/script.js rename index.css => client/style.css (100%) delete mode 100644 index.html delete mode 100644 scripts/deps.js delete mode 100644 scripts/index.js delete mode 100644 scripts/position-size-builder.js 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..ee2e494 --- /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 = Math.round(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: data.positionSizeUnit, + 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 100% rename from index.css rename to client/style.css diff --git a/index.html b/index.html deleted file mode 100644 index 09271c6..0000000 --- a/index.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - Trader Bruh - - - - -
- -
-
- -
-

Trader Bruh - v3.0

-

by @PseudoCode88

-
-
-
- -
- -
-
-
-

Position Size (units)

-

0

-
-
-

Position Size (USD)

-

$0

-
-
-

Margin (USD)

-

$0

-
-
-
- - -
-
-
-

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/index.js b/index.js index aca1b3c..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: 400, - minWidth: 400, - height: 752, - minHeight: 752, - 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/scripts/deps.js b/scripts/deps.js deleted file mode 100644 index 4af07bf..0000000 --- a/scripts/deps.js +++ /dev/null @@ -1 +0,0 @@ -const $ = require('jquery'); \ No newline at end of file diff --git a/scripts/index.js b/scripts/index.js deleted file mode 100644 index 4a6c68a..0000000 --- a/scripts/index.js +++ /dev/null @@ -1,13 +0,0 @@ -var db = {}; - -document.addEventListener('DOMContentLoaded', () => { - const modules = { - PositionSizeBuilder: PositionSizeBuilder($) - }; - - Object.values(modules).forEach(module => { - if (typeof module.init === 'function') { - module.init(); - } - }); -}); \ 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 e196ae2..0000000 --- a/scripts/position-size-builder.js +++ /dev/null @@ -1,97 +0,0 @@ -var PositionSizeBuilder = ($) => { - - var data = { - stopLoss: 0, - entryPrice: 0, - leverage: 1, - risk: 0, - direction: 'long', - positionSizeUnit: 0, - positionSizeUSD: 0, - margin: 0 - }; - - var 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') - } - } - - var eventBindings = () => { - Object.keys(el.textfield).forEach(function (id) { - el.textfield[id].on("keyup", updatePositionSize) - }) - } - - var 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() || '1'; - return acc; - }, {}); - } - - var updatePositionSize = () => { - const formData = getFormData(); - const data = calculatePositionSize(formData); - console.log(data); - updateData(data); - render(); - } - - var updateData = (formData) => { - Object.keys(formData).forEach((key) => { - data[key] = formData[key]; - }) - } - - var calculatePositionSize = (data) => { - const { risk, entryPrice, stopLoss, leverage } = data; - - const priceDifference = (stopLoss > entryPrice) ? stopLoss - entryPrice : entryPrice - stopLoss; - - data.positionSizeUnit = Math.round(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; - } - - var render = () => { - const elementsToUpdate = { - positionSizeUnit: data.positionSizeUnit, - positionSizeUSD: "$" + data.positionSizeUSD, - margin: "$" + data.margin - }; - - Object.entries(elementsToUpdate).forEach(([elementKey, value]) => { - el.label[elementKey].html(value); - }); - } - - var init = () => { - eventBindings(); - } - - return { - init: init - } -} \ No newline at end of file From 1590a360fc85981d14733bfbb27afe7ce3673b35 Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Thu, 12 Sep 2024 17:58:00 +0700 Subject: [PATCH 08/10] Remove file creation function from build script --- build.js | 93 +++++++++++++++----------------------------------------- 1 file changed, 25 insertions(+), 68 deletions(-) diff --git a/build.js b/build.js index e8e9e4c..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 = []; // 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 From 5493ff3b6650af5a94cfb5bb3f6f7c16da9a142a Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Thu, 12 Sep 2024 17:58:30 +0700 Subject: [PATCH 09/10] Modify package.json --- package.json | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ddda603..521e8b6 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,9 @@ "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,10 +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" } } \ No newline at end of file From 42a9b9a9b43901602d790d6507e07e0fb2f6306e Mon Sep 17 00:00:00 2001 From: pseudocode88 Date: Fri, 6 Jun 2025 19:43:54 +0700 Subject: [PATCH 10/10] Bug fix: position size precision --- client/script.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/script.js b/client/script.js index ee2e494..a5d86f7 100644 --- a/client/script.js +++ b/client/script.js @@ -64,7 +64,7 @@ let PositionSizeBuilder = ($) => { } let calculatePositionSize = (data) => { - const {risk, entryPrice, stopLoss, leverage} = data; + const { risk, entryPrice, stopLoss, leverage } = data; const priceDifference = (stopLoss > entryPrice) ? stopLoss - entryPrice : entryPrice - stopLoss; @@ -74,7 +74,7 @@ let PositionSizeBuilder = ($) => { data.positionSizeUSD = 0; } else { - data.positionSizeUnit = Math.round(risk / Math.abs(priceDifference)); + data.positionSizeUnit = risk / Math.abs(priceDifference); data.positionSizeUSD = (data.positionSizeUnit * entryPrice).toFixed(2); } @@ -86,7 +86,7 @@ let PositionSizeBuilder = ($) => { let render = () => { const elementsToUpdate = { - positionSizeUnit: data.positionSizeUnit, + positionSizeUnit: Number(data.positionSizeUnit).toFixed(4), positionSizeUSD: "$" + data.positionSizeUSD, margin: "$" + data.margin };