Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Customise the last buy price removing threshold #206

Merged
merged 19 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ data
log

.env
.vs
.vscode
pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 9 additions & 2 deletions app/cronjob/trailingTrade/step/remove-last-buy-price.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const {
getAPILimit,
isActionDisabled
} = require('../../trailingTradeHelper/common');
const { getConfiguration } = require('../../trailingTradeHelper/configuration');

/**
* Retrieve last buy order from cache
Expand All @@ -14,6 +15,7 @@ const {
* @param {*} symbol
* @returns
*/

const getLastBuyOrder = async (logger, symbol) => {
const cachedLastBuyOrder =
JSON.parse(await cache.get(`${symbol}-last-buy-order`)) || {};
Expand Down Expand Up @@ -169,15 +171,20 @@ const execute = async (logger, rawData) => {
return data;
}

if (baseAssetQuantity * currentPrice < parseFloat(minNotional)) {
//Get symbol config and define last buy remove price threshold, then get the calculated price.
const symbolConfiguration = rawData.symbolConfiguration;
pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
const lastBuyPriceRemoveThreshold = symbolConfiguration.buy.lastBuyPriceRemoveThreshold;
const priceCalculated = baseAssetQuantity * currentPrice;

if (priceCalculated < lastBuyPriceRemoveThreshold) {
// Final check for open orders
refreshedOpenOrders = await getAndCacheOpenOrdersForSymbol(logger, symbol);
if (refreshedOpenOrders.length > 0) {
logger.info('Do not remove last buy price. Found open orders.');
return data;
}

processMessage =
processMessage =
'Balance is less than the notional value. Delete last buy price.';

logger.error({ baseAssetQuantity }, processMessage);
Expand Down
84 changes: 82 additions & 2 deletions app/cronjob/trailingTradeHelper/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,74 @@ const getMaxPurchaseAmount = async (

pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
return newBuyMaxPurchaseAmount;
};

const getLastBuyPriceRemoveThreshold = async (
logger,
symbol,
globalConfiguration,
symbolConfiguration
) => {
const symbolBuyLastBuyPriceRemoveThreshold = _.get(
symbolConfiguration,
'buy.lastBuyPriceRemoveThreshold',
-1
);

if (symbolBuyLastBuyPriceRemoveThreshold !== -1) {
logger.info(
{ symbolBuyLastBuyPriceRemoveThreshold },
'Last buy threshold is found from symbol configuration.'
);
return symbolBuyLastBuyPriceRemoveThreshold;
}

logger.info(
{ symbolBuyLastBuyPriceRemoveThreshold },
'Last Buy Threshold is set as 10. Need to calculate and override it'
pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
);

let newBuyLastBuyPriceRemoveThreshold = -1;

// If old max purchase maount is -1, then should calculate maximum purchase amount based on the notional amount.
const cachedSymbolInfo =
pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
JSON.parse(
await cache.hget('trailing-trade-symbols', `${symbol}-symbol-info`)
) || {};

if (_.isEmpty(cachedSymbolInfo) === false) {
const {
quoteAsset,
filterMinNotional: { minNotional }
} = cachedSymbolInfo;

newBuyLastBuyPriceRemoveThreshold = _.get(
globalConfiguration,
`buy.lastBuyPriceRemoveThresholds.${quoteAsset}`,
-1
);

logger.info(
{ quoteAsset, newBuyLastBuyPriceRemoveThreshold },
'Retreived max purchase amount from global configuration'
);

if (newBuyLastBuyPriceRemoveThreshold === -1) {
newBuyLastBuyPriceRemoveThreshold = parseFloat(minNotional);

logger.info(
{ newBuyLastBuyPriceRemoveThreshold, minNotional },
'Could not get max purchase amount from global configuration. Use minimum notional from symbol info'
pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
);
}
} else {
logger.info(
{ cachedSymbolInfo },
'Could not find symbol info, wait to be cached.'
);
}

return newBuyLastBuyPriceRemoveThreshold;
};
/**
* Get global/symbol configuration
*
Expand Down Expand Up @@ -230,8 +298,20 @@ const getConfiguration = async (logger, symbol = null) => {
)
);

// For symbol configuration, remove maxPurchaseAmounts
_.unset(mergedConfigValue, 'buy.maxPurchaseAmounts');
_.set(
mergedConfigValue,
'buy.lastBuyPriceRemoveThreshold',
await getLastBuyPriceRemoveThreshold(
logger,
symbol,
globalConfigValue,
symbolConfigValue
)
);

// For symbol configuration, remove maxPurchaseAmounts
_.unset(mergedConfigValue, 'buy.maxPurchaseAmounts');
_.unset(mergedConfigValue, 'buy.lastBuyPriceRemoveThresholds');
}

// Merge global and symbol configuration
Expand Down
2 changes: 2 additions & 0 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
},
"buy": {
"enabled": true,
"lastBuyPriceRemoveThreshold": -1,
"lastBuyPriceRemoveThresholds": {},
"maxPurchaseAmount": -1,
"maxPurchaseAmounts": {},
"triggerPercentage": 1.0,
Expand Down
4 changes: 4 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@
type="text/babel"
src="./js/SettingIconMaxPurchaseAmount.js"
></script>
<script
type="text/babel"
src="./js/SettingIconLastBuyPriceRemoveThreshold.js"
></script>
<script type="text/babel" src="./js/SettingIcon.js"></script>
<script type="text/babel" src="./js/AccountWrapperAsset.js"></script>
<script type="text/babel" src="./js/AccountWrapper.js"></script>
Expand Down
56 changes: 49 additions & 7 deletions public/js/SettingIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ class SettingIcon extends React.Component {
this.handleMaxPurchaeAmountChange = this.handleMaxPurchaeAmountChange.bind(
this
);
this.handleLastBuyPriceRemoveThresholdChange = this.handleLastBuyPriceRemoveThresholdChange.bind(
this
);
}

getQuoteAssets(exchangeSymbols, selectedSymbols, maxPurchaseAmounts) {
getQuoteAssets(exchangeSymbols, selectedSymbols, maxPurchaseAmounts, lastBuyPriceRemoveThresholds) {
const quoteAssets = [];

selectedSymbols.forEach(symbol => {
Expand All @@ -43,9 +46,12 @@ class SettingIcon extends React.Component {
if (maxPurchaseAmounts[quoteAsset] === undefined) {
maxPurchaseAmounts[quoteAsset] = minNotional * 10;
}
if (lastBuyPriceRemoveThresholds[quoteAsset] == undefined) {
lastBuyPriceRemoveThresholds[quoteAsset] = minNotional;
}
});

return { quoteAssets, maxPurchaseAmounts };
return { quoteAssets, maxPurchaseAmounts, lastBuyPriceRemoveThresholds };
}

componentDidUpdate(nextProps) {
Expand All @@ -70,15 +76,20 @@ class SettingIcon extends React.Component {
if (configuration.buy.maxPurchaseAmounts === undefined) {
configuration.buy.maxPurchaseAmounts = {};
}
if (configuration.buy.lastBuyPriceRemoveThresholds === undefined) {
configuration.buy.lastBuyPriceRemoveThresholds = {};
}

// Set max purchase amount
const { quoteAssets, maxPurchaseAmounts } = this.getQuoteAssets(
// Set max purchase amount
const { quoteAssets, maxPurchaseAmounts, lastBuyPriceRemoveThresholds } = this.getQuoteAssets(
exchangeSymbols,
selectedSymbols,
configuration.buy.maxPurchaseAmounts
configuration.buy.maxPurchaseAmounts,
configuration.buy.lastBuyPriceRemoveThresholds
);

configuration.buy.maxPurchaseAmounts = maxPurchaseAmounts;
configuration.buy.lastBuyPriceRemoveThresholds = lastBuyPriceRemoveThresholds;

this.setState({
availableSymbols,
Expand Down Expand Up @@ -145,6 +156,20 @@ class SettingIcon extends React.Component {
});
}

handleLastBuyPriceRemoveThresholdChange(newLastBuyPriceRemoveThresholds) {
console.log('handleLastBuyPriceRemoveThresholdChange => ', newLastBuyPriceRemoveThresholds);

const { configuration } = this.state;

this.setState({
configuration: _.set(
configuration,
'buy.lastBuyPriceRemoveThresholds',
newLastBuyPriceRemoveThresholds
)
});
}

render() {
const { configuration, availableSymbols, quoteAssets } = this.state;
const { symbols: selectedSymbols } = configuration;
Expand Down Expand Up @@ -203,14 +228,17 @@ class SettingIcon extends React.Component {

const {
quoteAssets,
maxPurchaseAmounts
maxPurchaseAmounts,
lastBuyPriceRemoveThresholds
} = this.getQuoteAssets(
exchangeSymbols,
selected,
configuration.buy.maxPurchaseAmounts
configuration.buy.maxPurchaseAmounts,
configuration.buy.lastBuyPriceRemoveThresholds,
);

configuration.buy.maxPurchaseAmounts = maxPurchaseAmounts;
configuration.buy.lastBuyPriceRemoveThresholds = lastBuyPriceRemoveThresholds;
this.setState({ configuration, quoteAssets });
}}
size='sm'
Expand Down Expand Up @@ -381,6 +409,9 @@ class SettingIcon extends React.Component {
</Form.Check.Label>
</Form.Check>
</Form.Group>



<SettingIconMaxPurchaseAmount
quoteAssets={quoteAssets}
maxPurchaseAmounts={
Expand All @@ -390,6 +421,17 @@ class SettingIcon extends React.Component {
this.handleMaxPurchaeAmountChange
}
/>

<SettingIconLastBuyPriceRemoveThreshold
quoteAssets={quoteAssets}
lastBuyPriceRemoveThresholds={
configuration.buy.lastBuyPriceRemoveThresholds
}
handleLastBuyPriceRemoveThresholdChange={
this.handleLastBuyPriceRemoveThresholdChange
}
/>

<Form.Group
controlId='field-buy-trigger-percentage'
className='mb-2'>
Expand Down
109 changes: 109 additions & 0 deletions public/js/SettingIconLastBuyPriceRemoveThreshold.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* eslint-disable no-unused-vars */
/* eslint-disable react/jsx-no-undef */
/* eslint-disable no-undef */
class SettingIconLastBuyPriceRemoveThreshold extends React.Component {
constructor(props) {
super(props);

this.state = {
lastBuyPriceRemoveThresholds: {}
};

this.handleInputChange = this.handleInputChange.bind(this);
}

componentDidUpdate(nextProps) {
// Only update configuration, when the modal is closed and different.
if (
_.isEmpty(nextProps.lastBuyPriceRemoveThresholds) === false &&
_.isEqual(nextProps.lastBuyPriceRemoveThresholds, this.state.lastBuyPriceRemoveThresholds) ===
false
) {
const { lastBuyPriceRemoveThresholds } = nextProps;
console.log('lastBuyPriceRemoveThreshold has changed', { lastBuyPriceRemoveThresholds });
this.setState({
lastBuyPriceRemoveThresholds
});
}
}

handleInputChange(event) {
const target = event.target;
const value =
target.type === 'checkbox'
? target.checked
: target.type === 'number'
? +target.value
: target.value;
const stateKey = target.getAttribute('data-state-key');

const { lastBuyPriceRemoveThresholds } = this.state;

console.log(
'_.set(lastBuyPriceRemoveThresholds, stateKey, value) => ',
_.set(lastBuyPriceRemoveThresholds, stateKey, value)
);

const newLastBuyPriceRemoveThreshold = _.set(lastBuyPriceRemoveThresholds, stateKey, value);
this.setState({
lastBuyPriceRemoveThresholds: newLastBuyPriceRemoveThreshold
});

this.props.handleLastBuyPriceRemoveThresholdChange(lastBuyPriceRemoveThresholds);
}

render() {
const { quoteAssets } = this.props;
const { lastBuyPriceRemoveThresholds } = this.state;

if (_.isEmpty(lastBuyPriceRemoveThresholds)) {
return '';
}

return quoteAssets.map((quoteAsset, index) => {
return (
<div
key={quoteAsset + '-' + index}
className='coin-info-last-buy-threshold-wrapper'>
<Form.Group
controlId={'field-min-last-buy-limit-percentage-' + quoteAsset}
className='mb-2'>
<Form.Label className='mb-0'>
Last Buy Threshold for {quoteAsset}{' '}
pedrohusky marked this conversation as resolved.
Show resolved Hide resolved
<OverlayTrigger
trigger='click'
key={'last-buy-threshold-overlay-' + quoteAsset}
placement='bottom'
overlay={
<Popover
id={'last-buy-threshold-overlay-right' + quoteAsset}>
<Popover.Content>
Set the last buy threshold for symbols with quote asset "
{quoteAsset}". The last buy threshold will be applied to
the symbols which ends with "{quoteAsset}" if not
configured the symbol configuration.
</Popover.Content>
</Popover>
}>
<Button variant='link' className='p-0 m-0 ml-1 text-info'>
<i className='fa fa-question-circle'></i>
</Button>
</OverlayTrigger>
</Form.Label>
<Form.Control
size='sm'
type='number'
placeholder={'Enter last buy threshold for ' + quoteAsset}
required
min='1'
step='0.0001'
data-state-key={quoteAsset}
value={lastBuyPriceRemoveThresholds[quoteAsset]}
onChange={this.handleInputChange}
/>
</Form.Group>
</div>
);
});
}
}
Loading