mirror of https://github.com/ghostfolio/ghostfolio
Browse Source
* Clean up initial (original) values from X-Ray * Refactor current to valueInBaseCurrency * Update changelogpull/1915/head
Thomas Kaul
2 years ago
committed by
GitHub
12 changed files with 30 additions and 282 deletions
@ -1,88 +0,0 @@ |
|||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; |
|||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; |
|||
import { |
|||
PortfolioDetails, |
|||
PortfolioPosition, |
|||
UserSettings |
|||
} from '@ghostfolio/common/interfaces'; |
|||
|
|||
import { Rule } from '../../rule'; |
|||
|
|||
export class AccountClusterRiskInitialInvestment extends Rule<Settings> { |
|||
public constructor( |
|||
protected exchangeRateDataService: ExchangeRateDataService, |
|||
private accounts: PortfolioDetails['accounts'] |
|||
) { |
|||
super(exchangeRateDataService, { |
|||
name: 'Initial Investment' |
|||
}); |
|||
} |
|||
|
|||
public evaluate(ruleSettings?: Settings) { |
|||
const accounts: { |
|||
[symbol: string]: Pick<PortfolioPosition, 'name'> & { |
|||
investment: number; |
|||
}; |
|||
} = {}; |
|||
|
|||
for (const [accountId, account] of Object.entries(this.accounts)) { |
|||
accounts[accountId] = { |
|||
name: account.name, |
|||
investment: account.original |
|||
}; |
|||
} |
|||
|
|||
let maxItem; |
|||
let totalInvestment = 0; |
|||
|
|||
for (const account of Object.values(accounts)) { |
|||
if (!maxItem) { |
|||
maxItem = account; |
|||
} |
|||
|
|||
// Calculate total investment
|
|||
totalInvestment += account.investment; |
|||
|
|||
// Find maximum
|
|||
if (account.investment > maxItem?.investment) { |
|||
maxItem = account; |
|||
} |
|||
} |
|||
|
|||
const maxInvestmentRatio = maxItem.investment / totalInvestment; |
|||
|
|||
if (maxInvestmentRatio > ruleSettings.threshold) { |
|||
return { |
|||
evaluation: `Over ${ |
|||
ruleSettings.threshold * 100 |
|||
}% of your initial investment is at ${maxItem.name} (${( |
|||
maxInvestmentRatio * 100 |
|||
).toPrecision(3)}%)`,
|
|||
value: false |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
evaluation: `The major part of your initial investment is at ${ |
|||
maxItem.name |
|||
} (${(maxInvestmentRatio * 100).toPrecision(3)}%) and does not exceed ${ |
|||
ruleSettings.threshold * 100 |
|||
}%`,
|
|||
value: true |
|||
}; |
|||
} |
|||
|
|||
public getSettings(aUserSettings: UserSettings): Settings { |
|||
return { |
|||
baseCurrency: aUserSettings.baseCurrency, |
|||
isActive: true, |
|||
threshold: 0.5 |
|||
}; |
|||
} |
|||
} |
|||
|
|||
interface Settings extends RuleSettings { |
|||
baseCurrency: string; |
|||
isActive: boolean; |
|||
threshold: number; |
|||
} |
@ -1,71 +0,0 @@ |
|||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; |
|||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; |
|||
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces'; |
|||
|
|||
import { Rule } from '../../rule'; |
|||
|
|||
export class CurrencyClusterRiskBaseCurrencyInitialInvestment extends Rule<Settings> { |
|||
public constructor( |
|||
protected exchangeRateDataService: ExchangeRateDataService, |
|||
private positions: TimelinePosition[] |
|||
) { |
|||
super(exchangeRateDataService, { |
|||
name: 'Initial Investment: Base Currency' |
|||
}); |
|||
} |
|||
|
|||
public evaluate(ruleSettings: Settings) { |
|||
const positionsGroupedByCurrency = this.groupCurrentPositionsByAttribute( |
|||
this.positions, |
|||
'currency', |
|||
ruleSettings.baseCurrency |
|||
); |
|||
|
|||
let maxItem = positionsGroupedByCurrency[0]; |
|||
let totalInvestment = 0; |
|||
|
|||
positionsGroupedByCurrency.forEach((groupItem) => { |
|||
// Calculate total investment
|
|||
totalInvestment += groupItem.investment; |
|||
|
|||
// Find maximum
|
|||
if (groupItem.investment > maxItem.investment) { |
|||
maxItem = groupItem; |
|||
} |
|||
}); |
|||
|
|||
const baseCurrencyItem = positionsGroupedByCurrency.find((item) => { |
|||
return item.groupKey === ruleSettings.baseCurrency; |
|||
}); |
|||
|
|||
const baseCurrencyInvestmentRatio = |
|||
baseCurrencyItem?.investment / totalInvestment || 0; |
|||
|
|||
if (maxItem.groupKey !== ruleSettings.baseCurrency) { |
|||
return { |
|||
evaluation: `The major part of your initial investment is not in your base currency (${( |
|||
baseCurrencyInvestmentRatio * 100 |
|||
).toPrecision(3)}% in ${ruleSettings.baseCurrency})`,
|
|||
value: false |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
evaluation: `The major part of your initial investment is in your base currency (${( |
|||
baseCurrencyInvestmentRatio * 100 |
|||
).toPrecision(3)}% in ${ruleSettings.baseCurrency})`,
|
|||
value: true |
|||
}; |
|||
} |
|||
|
|||
public getSettings(aUserSettings: UserSettings): Settings { |
|||
return { |
|||
baseCurrency: aUserSettings.baseCurrency, |
|||
isActive: true |
|||
}; |
|||
} |
|||
} |
|||
|
|||
interface Settings extends RuleSettings { |
|||
baseCurrency: string; |
|||
} |
@ -1,72 +0,0 @@ |
|||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; |
|||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; |
|||
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces'; |
|||
|
|||
import { Rule } from '../../rule'; |
|||
|
|||
export class CurrencyClusterRiskInitialInvestment extends Rule<Settings> { |
|||
public constructor( |
|||
protected exchangeRateDataService: ExchangeRateDataService, |
|||
private positions: TimelinePosition[] |
|||
) { |
|||
super(exchangeRateDataService, { |
|||
name: 'Initial Investment' |
|||
}); |
|||
} |
|||
|
|||
public evaluate(ruleSettings: Settings) { |
|||
const positionsGroupedByCurrency = this.groupCurrentPositionsByAttribute( |
|||
this.positions, |
|||
'currency', |
|||
ruleSettings.baseCurrency |
|||
); |
|||
|
|||
let maxItem = positionsGroupedByCurrency[0]; |
|||
let totalInvestment = 0; |
|||
|
|||
positionsGroupedByCurrency.forEach((groupItem) => { |
|||
// Calculate total investment
|
|||
totalInvestment += groupItem.investment; |
|||
|
|||
// Find maximum
|
|||
if (groupItem.investment > maxItem.investment) { |
|||
maxItem = groupItem; |
|||
} |
|||
}); |
|||
|
|||
const maxInvestmentRatio = maxItem.investment / totalInvestment; |
|||
|
|||
if (maxInvestmentRatio > ruleSettings.threshold) { |
|||
return { |
|||
evaluation: `Over ${ |
|||
ruleSettings.threshold * 100 |
|||
}% of your initial investment is in ${maxItem.groupKey} (${( |
|||
maxInvestmentRatio * 100 |
|||
).toPrecision(3)}%)`,
|
|||
value: false |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
evaluation: `The major part of your initial investment is in ${ |
|||
maxItem.groupKey |
|||
} (${(maxInvestmentRatio * 100).toPrecision(3)}%) and does not exceed ${ |
|||
ruleSettings.threshold * 100 |
|||
}%`,
|
|||
value: true |
|||
}; |
|||
} |
|||
|
|||
public getSettings(aUserSettings: UserSettings): Settings { |
|||
return { |
|||
baseCurrency: aUserSettings.baseCurrency, |
|||
isActive: true, |
|||
threshold: 0.5 |
|||
}; |
|||
} |
|||
} |
|||
|
|||
interface Settings extends RuleSettings { |
|||
baseCurrency: string; |
|||
threshold: number; |
|||
} |
Loading…
Reference in new issue