Skip to content
This repository was archived by the owner on Feb 22, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 135 additions & 59 deletions src/botPage/view/Dialogs/Limits.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,122 @@
import { LiveApi } from 'binary-live-api';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { translate } from '../../../common/i18n';
import * as style from '../style';
import Dialog from './Dialog';
import { restrictInputCharacter } from '../shared';
import * as style from '../style';
import { getToken } from '../../../common/utils/storageManager';
import { showSpinnerInButton, removeSpinnerInButton, createUrl, translate } from '../../../common/utils/tools';

class LimitsContent extends PureComponent {
constructor() {
super();
this.state = {
error : '',
maxLoss : '',
maxTrades: '',
maxTrades: 0,
maxLosses: null,
};
}

submit() {
const maxLoss = parseFloat(this.state.maxLoss || 0);
const maxTrades = parseInt(this.state.maxTrades || 0);
this.setState({ error: '' });
if (maxTrades <= 0 || maxTrades > 100) {
this.setState({ error: 'Maximum number of trades should be between 1 and 100.' });

const onSave = () => {
this.props.onSave({
maxTrades: this.state.maxTrades,
maxLoss : this.state.maxLosses,
});
};

if (!this.state.maxLosses) {
this.updateMaxLosses()
.then(() => {
onSave();
})
.catch(() => {
this.setState({
error: translate(
'Please set your daily loss limit in the Self-Exclusion Facilities page to allow trading.'
),
});
});
return;
}
if (!maxLoss) {
this.setState({ error: 'Please enter a Maximum Loss amount greater than zero.' });

if (this.state.maxTrades <= 0 || this.state.maxTrades > 100) {
this.setState({ error: translate('Maximum consecutive trades should be between 1 and 100') });
return;
}
this.props.onSave({
maxLoss,
maxTrades,

onSave();
}

updateMaxLosses() {
return new Promise((resolve, reject) => {
const { api } = this.props;
const $startButton = $('#submit-trade-limits');
const initialText = $startButton.text();

showSpinnerInButton($startButton);

api.getSelfExclusion()
.then(response => {
const { max_losses: maxLosses } = response.get_self_exclusion;
let callback;

if (maxLosses) {
this.setState({ maxLosses });
callback = resolve;
} else {
callback = reject;
}

removeSpinnerInButton($startButton, initialText);
callback();
})
.catch(() => {
removeSpinnerInButton($startButton, initialText);
reject();
});
});
}

componentDidMount() {
const cleanupLayout = () => {
this.setState({
maxTrades: '',
maxLoss : '',
maxTrades: 0,
error : '',
});
};

const onDialogOpen = () => {
this.updateMaxLosses().catch(() => {});
};

$('#limits-dialog-component').dialog({
open : onDialogOpen,
close : cleanupLayout,
autoOpen: false,
});
}

onMaxTradeChange(e) {
if (restrictInputCharacter({ input: e.target.value, whitelistRegEx: '^[\\d]*$' })) {
this.setState({ maxTrades: e.target.value });
}
}
onMaxLossChange(e) {
if (restrictInputCharacter({ input: e.target.value, whitelistRegEx: '^\\d*\\.?\\d*$' })) {
this.setState({ maxLoss: e.target.value });

getDailyLossesLimit() {
if (this.state.maxLosses) {
const token = $('.account-id')
.first()
.attr('value');
const tokenObj = getToken(token);
const currency = tokenObj && tokenObj.loginInfo.currency;
return currency ? `${this.state.maxLosses} ${currency}` : `${this.state.maxLosses}`;
}
return translate('Not set');
}

render() {
return (
<form
Expand All @@ -62,65 +125,78 @@ class LimitsContent extends PureComponent {
className="dialog-content"
style={style.content}
>
<div>
<div style={style.inputRow}>
<label style={style.field} htmlFor="limitation-max-trades">
<input
style={style.input}
ref={el => {
this.maxTradesDiv = el;
}}
type="text"
id="limitation-max-trades"
step="1"
maxLength="3"
value={this.state.maxTrades}
onChange={(...args) => this.onMaxTradeChange(...args)}
/>
{translate('Maximum number of trades')}
</label>
</div>
<div style={style.inputRow}>
<label style={style.field} htmlFor="limitation-max-loss">
<input
style={style.input}
ref={el => {
this.maxLossDiv = el;
}}
value={this.state.maxLoss}
type="text"
id="limitation-max-loss"
step="any"
onChange={(...args) => this.onMaxLossChange(...args)}
/>
{translate('Maximum loss amount')}
</label>
</div>
{this.state.error ? <p style={style.error}>{this.state.error}</p> : null}
</div>
<p>
{translate(
'Trade limitations are required by our regulators. Your bot will conclude trading when one or both of the conditions are met.'
'We require you to set trade limitations in compliance with business regulations. Please note that your bot will only stop trading if any or both of the conditions below are met.'
)}
</p>
<div style={style.submitButton}>
<button type="submit">{translate('Start')}</button>
<div className="input-row">
<label>
{translate('Daily limit on losses:')} <strong>{this.getDailyLossesLimit()}</strong>
</label>
<div className="description">
{translate([
'This is the threshold that limits your potential losses for the day in all Binary.com platforms. Once your total loss reaches or exceeds this amount, your bot will stop trading. Please set a value in the [_1]Self-Exclusion Facilities page[_2].',
`<a href="${createUrl({
addLanguage : true,
path : 'user/security/self_exclusionws',
addHtmlExtension: true,
isNonBotPage : true,
})}" target="_blank">`,
'</a>',
])}
</div>
</div>
<div className="input-row">
<label htmlFor="limitation-max-trades">{translate('Maximum consecutive trades')}</label>
<div className="description">
{translate(
'This is the maximum number of trades that you allow your bot to execute for this run.'
)}
</div>
</div>
<div className="input-row">
<input
ref={el => {
this.maxTradesDiv = el;
}}
type="text"
id="limitation-max-trades"
step="1"
maxLength="3"
value={this.state.maxTrades}
onChange={(...args) => this.onMaxTradeChange(...args)}
data-lpignore={true}
/>
</div>
{this.state.error && <p style={style.error}>{this.state.error}</p>}
<div className="input-row last" style={style.submitButton}>
<button id="submit-trade-limits" type="submit">
{translate('Start')}
</button>
</div>
</form>
);
}
static props = {
onSave: PropTypes.func,
api : PropTypes.instanceOf(LiveApi),
};
}

export default class Limits extends Dialog {
constructor() {
constructor(api) {
const onSave = limits => {
this.limitsPromise(limits);
this.close();
};
super('limits-dialog', translate('Trade Limitations'), <LimitsContent onSave={onSave} />, style.dialogLayout);
super(
'limits-dialog',
translate('Trade Limitations'),
<LimitsContent onSave={onSave} api={api} />,
style.dialogLayout
);
this.registerCloseOnOtherDialog();
}
getLimits() {
this.open();
Expand Down
8 changes: 6 additions & 2 deletions src/botPage/view/View.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ const clearRealityCheck = () => {
stopRealityCheck();
};

const limits = new Limits();
const integrationsDialog = new IntegrationsDialog();
const loadDialog = new LoadDialog();
const saveDialog = new SaveDialog();
Expand Down Expand Up @@ -518,8 +517,13 @@ export default class View {
.attr('value');
const tokenObj = getToken(token);
initRealityCheck(() => $('#stopButton').triggerHandler('click'));

if (tokenObj && tokenObj.hasTradeLimitation) {
limits.getLimits().then(startBot);
const limits = new Limits(api);
limits
.getLimits()
.then(startBot)
.catch(() => {});
} else {
startBot();
}
Expand Down
37 changes: 18 additions & 19 deletions static/css/_panel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,24 @@ $disabled-color: #F2F2F2;

.ui-dialog-content {
padding: 0px !important;

&.ui-widget-content {
input[type=text] {
height: 40px;
width: 100%;
}
.description {
font-size: 75%;
margin: 0.5em 0;
}
.input-row {
margin: 1em 0;

&.last {
margin-bottom: 0;
}
}
}
}

#load-dialog, #save-dialog {
Expand All @@ -328,23 +346,7 @@ $disabled-color: #F2F2F2;
}
}

#load-dialog, #save-dialog, #integrations-dialog {
.input-row {
margin: 1em 0;
}
.input-row.last {
margin-bottom: 0;
}
& .description {
font-size: 75%;
}
}

#save-dialog {
#save-filename {
width: 100%;
height: 40px;
}
#collection {
padding: 1.2em;
border: 1px solid $brand-gray;
Expand All @@ -367,9 +369,6 @@ $disabled-color: #F2F2F2;
font-size: 20px;
margin: 0 0 0.2em 0;
}
.description {
margin: 0 0 0.2em 0;
}
.left {
width: 60%;
display: table-cell;
Expand Down