UNPKG

minimalist-money-management-calculator

Version:

Set of utility functions for CFD money management with bunjs

98 lines (86 loc) 3.9 kB
import { Strategy, Market, TradeInfo, Volume } from './types'; export class Risk { private readonly CURRENCY_DECIMALS = 2; constructor(private readonly strategy: Strategy) {} /** * Volume for one trade * @param market Market * @param tradeInfo TradeInfo * @param floor boolean, default false, Volume are rounds to the neariest volume possible by your broker (Market.lotStep), pass true for the lowest * @returns Volume, * @example * 20 stop points, * 1000E balance, * 1% de risk, * Minimum volume, * * 1% of 1000 => 10$, * 10/20 => 0.5$ per point, * Value of a standart contract (≃ 375000 for DAX40) / DAX40 current price (15000) => 25 (lot in euros per point), * 0.5 / 25 (lot in euros per point) => 0.02 lot */ public volume(market: Market, tradeInfo: TradeInfo, floor: boolean = false): Volume | Error { if (!Number.isInteger(tradeInfo.stopDistance) || tradeInfo.stopDistance < 1) { return new Error('StopDistance has to be integrer, minimum 1 !'); } const riskMaxPerPos: number = this.strategy.initialBalance * (this.strategy.riskPerPos / 100); // In euros const riskPerPoint: number = riskMaxPerPos / tradeInfo.stopDistance; // In euros const currencyPerPipPerLot: number = market.unitPerLotStandard; // In euros for one full contract const volumePerPipPerLotStep: number = currencyPerPipPerLot * market.lotStep; const posVolume: number = riskPerPoint / currencyPerPipPerLot; if ((volumePerPipPerLotStep * (posVolume / market.lotStep)).toFixed(this.CURRENCY_DECIMALS) === riskPerPoint.toFixed(this.CURRENCY_DECIMALS)) { const forcedToMinimum = posVolume < market.lotStep; const finalVol = floor ? parseFloat(Math.floor(posVolume).toFixed(this.CURRENCY_DECIMALS)) : parseFloat(posVolume.toFixed(this.CURRENCY_DECIMALS)); if (posVolume < market.lotStep) { return { lot: market.lotStep, forcedToMinimum: forcedToMinimum }; } return { lot: finalVol, forcedToMinimum: forcedToMinimum }; } else { return new Error('Something went wrong when try to calcul volume'); } } // forexVolume(market: Market, tradeInfo: TradeInfo, floor: boolean = false, effectiveEntry, market, tradeInfo, investorConfig) { // const inst = tradeInfo.trade.inst; // const point = market.instInfo.tickSize * 10; // const oneLotValue = market.instInfo.contractSize; // const oneLotMargin = (market.instInfo.leverage * oneLotValue) / 100; // valuePerPipPerLot = ( // (market.instInfo.contractSize / effectiveEntry) * // point // ).toFixed(EUROS_DECIMALS); // En euros pour un lot plein // valuePerPipPerMicroLot = valuePerPipPerLot / 100, // riskMaxPerPos = // investorConfig.virtualBalance * (investorConfig.riskPerPos / 100); // En euros // stopInitialSize = Math.abs( // (tradeInfo.trade.stop - tradeInfo.trade.entry).toFixed(market.digits) // ); // en Pips float // const stopAbsolute = stopInitialSize / point; // en points // const riskPerPoint = riskMaxPerPos / stopAbsolute; // en euros // const posVolume = riskPerPoint / valuePerPipPerLot; // if ( // (valuePerPipPerMicroLot * (posVolume / market.instInfo.lotStep)).toFixed( // EUROS_DECIMALS // ) === riskPerPoint.toFixed(EUROS_DECIMALS) // ) { // const finalVol = parseFloat(posVolume.toFixed(EUROS_DECIMALS)); // if (finalVol === 0) { // console.log(`Volume de transation à 0, décalage vers un volume minimum`); // return 0.01; // } // console.log(`Volume de transation :${finalVol}`); // return parseFloat(finalVol); // } else { // // BUG Stopper le trade en cours, lorsque cette erreur est call // throw new Error( // `Le volume de trading n'est pas correct, sur ${inst}`, // "risk => forexVolume" // ); // } // } }