Refactor positions
This commit is contained in:
parent
fdc89f7182
commit
1226c26a9d
@ -3,10 +3,7 @@ import {
|
||||
GetValueObject
|
||||
} from '@ghostfolio/api/app/core/current-rate.service';
|
||||
import { OrderType } from '@ghostfolio/api/models/order-type';
|
||||
import {
|
||||
MarketState,
|
||||
Type
|
||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import { resetHours } from '@ghostfolio/common/helper';
|
||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||
import { Currency } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
@ -24,7 +21,6 @@ import {
|
||||
subDays
|
||||
} from 'date-fns';
|
||||
import { flatten } from 'lodash';
|
||||
import { resetHours } from '@ghostfolio/common/helper';
|
||||
|
||||
const DATE_FORMAT = 'yyyy-MM-dd';
|
||||
|
||||
@ -145,19 +141,15 @@ export class PortfolioCalculator {
|
||||
averagePrice: item.investment.div(item.quantity),
|
||||
currency: item.currency,
|
||||
firstBuyDate: item.firstBuyDate,
|
||||
marketState: MarketState.open, // TODO
|
||||
quantity: item.quantity,
|
||||
symbol: item.symbol,
|
||||
investment: item.investment,
|
||||
marketPrice: marketValue?.marketPrice,
|
||||
transactionCount: item.transactionCount,
|
||||
grossPerformance,
|
||||
grossPerformancePercentage: marketValue
|
||||
? grossPerformance.div(item.investment)
|
||||
: null,
|
||||
url: '', // TODO
|
||||
name: '', // TODO,
|
||||
type: Type.Unknown // TODO
|
||||
investment: item.investment,
|
||||
marketPrice: marketValue?.marketPrice,
|
||||
quantity: item.quantity,
|
||||
symbol: item.symbol,
|
||||
transactionCount: item.transactionCount
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||
import { Position } from '@ghostfolio/common/interfaces';
|
||||
|
||||
export interface PortfolioPositions {
|
||||
positions: TimelinePosition[];
|
||||
positions: Position[];
|
||||
}
|
||||
|
@ -283,9 +283,13 @@ export class PortfolioController {
|
||||
@Get('positions')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getPositions(
|
||||
@Headers('impersonation-id') impersonationId
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Query('range') range
|
||||
): Promise<PortfolioPositions> {
|
||||
const positions = await this.portfolioService.getPositions(impersonationId);
|
||||
const positions = await this.portfolioService.getPositions(
|
||||
impersonationId,
|
||||
range
|
||||
);
|
||||
|
||||
return { positions };
|
||||
}
|
||||
|
@ -14,10 +14,15 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider.serv
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service';
|
||||
import { IOrder } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import {
|
||||
MarketState,
|
||||
Type
|
||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import { RulesService } from '@ghostfolio/api/services/rules.service';
|
||||
import {
|
||||
PortfolioItem,
|
||||
PortfolioOverview
|
||||
PortfolioOverview,
|
||||
Position
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { DateRange, RequestWithUser } from '@ghostfolio/common/types';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
@ -192,7 +197,10 @@ export class PortfolioService {
|
||||
}));
|
||||
}
|
||||
|
||||
public async getPositions(aImpersonationId: string) {
|
||||
public async getPositions(
|
||||
aImpersonationId: string,
|
||||
aDateRange: DateRange = 'max'
|
||||
): Promise<Position[]> {
|
||||
const impersonationUserId =
|
||||
await this.impersonationService.validateImpersonationId(
|
||||
aImpersonationId,
|
||||
@ -210,13 +218,23 @@ export class PortfolioService {
|
||||
|
||||
portfolioCalculator.setTransactionPoints(transactionPoints);
|
||||
|
||||
// TODO: get positions for date range
|
||||
console.log('Date range:', aDateRange);
|
||||
const positions = await portfolioCalculator.getCurrentPositions();
|
||||
|
||||
return Object.values(positions).map((position) => {
|
||||
return {
|
||||
...position,
|
||||
grossPerformance: Number(position.grossPerformance),
|
||||
grossPerformancePercentage: Number(position.grossPerformancePercentage)
|
||||
averagePrice: new Big(position.averagePrice).toNumber(),
|
||||
grossPerformance: new Big(position.grossPerformance).toNumber(),
|
||||
grossPerformancePercentage: new Big(
|
||||
position.grossPerformancePercentage
|
||||
).toNumber(),
|
||||
investment: new Big(position.investment).toNumber(),
|
||||
name: '', // TODO
|
||||
quantity: new Big(position.quantity).toNumber(),
|
||||
type: Type.Unknown, // TODO
|
||||
url: '' // TODO
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ export class Portfolio implements PortfolioInterface {
|
||||
|
||||
this.getSymbols().forEach((symbol) => {
|
||||
positions[symbol] = {
|
||||
symbol,
|
||||
averagePrice: portfolioItemsYesterday?.positions[symbol]?.averagePrice,
|
||||
currency: portfolioItemsYesterday?.positions[symbol]?.currency,
|
||||
firstBuyDate: portfolioItemsYesterday?.positions[symbol]?.firstBuyDate,
|
||||
@ -723,6 +724,7 @@ export class Portfolio implements PortfolioInterface {
|
||||
const positions: { [symbol: string]: Position } = {};
|
||||
this.getSymbols().forEach((symbol) => {
|
||||
positions[symbol] = {
|
||||
symbol,
|
||||
averagePrice: 0,
|
||||
currency: undefined,
|
||||
firstBuyDate: null,
|
||||
@ -759,12 +761,13 @@ export class Portfolio implements PortfolioInterface {
|
||||
|
||||
const yesterday = getYesterday();
|
||||
|
||||
let positions: { [symbol: string]: Position } = {};
|
||||
const positions: { [symbol: string]: Position } = {};
|
||||
|
||||
if (isAfter(yesterday, this.getMinDate())) {
|
||||
// Add yesterday
|
||||
this.getSymbols().forEach((symbol) => {
|
||||
positions[symbol] = {
|
||||
symbol,
|
||||
averagePrice: 0,
|
||||
currency: undefined,
|
||||
firstBuyDate: null,
|
||||
@ -773,6 +776,7 @@ export class Portfolio implements PortfolioInterface {
|
||||
marketPrice:
|
||||
historicalData[symbol]?.[format(yesterday, 'yyyy-MM-dd')]
|
||||
?.marketPrice || 0,
|
||||
name: '',
|
||||
quantity: 0,
|
||||
transactionCount: 0
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||
import { Position } from '@ghostfolio/common/interfaces';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@ -25,7 +25,7 @@ export class PositionComponent implements OnDestroy, OnInit {
|
||||
@Input() deviceType: string;
|
||||
@Input() isLoading: boolean;
|
||||
@Input() locale: string;
|
||||
@Input() position: TimelinePosition;
|
||||
@Input() position: Position;
|
||||
@Input() range: string;
|
||||
|
||||
public unknownKey = UNKNOWN_KEY;
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
MarketState,
|
||||
Type
|
||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||
import { Position } from '@ghostfolio/common/interfaces';
|
||||
|
||||
@Component({
|
||||
selector: 'gf-positions',
|
||||
@ -21,12 +21,12 @@ export class PositionsComponent implements OnChanges, OnInit {
|
||||
@Input() baseCurrency: string;
|
||||
@Input() deviceType: string;
|
||||
@Input() locale: string;
|
||||
@Input() positions: TimelinePosition[];
|
||||
@Input() positions: Position[];
|
||||
@Input() range: string;
|
||||
|
||||
public hasPositions: boolean;
|
||||
public positionsRest: TimelinePosition[] = [];
|
||||
public positionsWithPriority: TimelinePosition[] = [];
|
||||
public positionsRest: Position[] = [];
|
||||
public positionsWithPriority: Position[] = [];
|
||||
|
||||
private ignoreTypes = [Type.Cash];
|
||||
|
||||
|
@ -24,7 +24,7 @@ import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||
import {
|
||||
PortfolioOverview,
|
||||
PortfolioPerformance,
|
||||
TimelinePosition,
|
||||
Position,
|
||||
User
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
@ -65,7 +65,7 @@ export class HomePageComponent implements AfterViewInit, OnDestroy, OnInit {
|
||||
public isLoadingPerformance = true;
|
||||
public overview: PortfolioOverview;
|
||||
public performance: PortfolioPerformance;
|
||||
public positions: TimelinePosition[];
|
||||
public positions: Position[];
|
||||
public routeQueryParams: Subscription;
|
||||
public user: User;
|
||||
|
||||
@ -231,14 +231,11 @@ export class HomePageComponent implements AfterViewInit, OnDestroy, OnInit {
|
||||
});
|
||||
|
||||
this.dataService
|
||||
.fetchPositions(/* { range: this.dateRange } */) // TODO
|
||||
.fetchPositions({ range: this.dateRange })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((response) => {
|
||||
console.log(response);
|
||||
|
||||
this.positions = response.positions;
|
||||
this.hasPositions =
|
||||
this.positions && Object.keys(this.positions).length > 1;
|
||||
this.hasPositions = this.positions?.length > 0;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
|
@ -107,7 +107,6 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
});
|
||||
|
||||
this.fetchOrders();
|
||||
this.fetchPositions();
|
||||
}
|
||||
|
||||
public fetchOrders() {
|
||||
@ -125,15 +124,6 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
public fetchPositions() {
|
||||
this.dataService
|
||||
.fetchPositions()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((response) => {
|
||||
console.log(response);
|
||||
});
|
||||
}
|
||||
|
||||
public onCloneTransaction(aTransaction: OrderModel) {
|
||||
this.openCreateTransactionDialog(aTransaction);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
User
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { permissions } from '@ghostfolio/common/permissions';
|
||||
import { DateRange } from '@ghostfolio/common/types';
|
||||
import { Order as OrderModel } from '@prisma/client';
|
||||
import { Account as AccountModel } from '@prisma/client';
|
||||
import { parseISO } from 'date-fns';
|
||||
@ -84,9 +85,9 @@ export class DataService {
|
||||
return this.http.get<Access[]>('/api/access');
|
||||
}
|
||||
|
||||
public fetchChart(aParams: { [param: string]: any }) {
|
||||
public fetchChart({ range }: { range: DateRange }) {
|
||||
return this.http.get<HistoricalDataItem[]>('/api/portfolio/chart', {
|
||||
params: aParams
|
||||
params: { range }
|
||||
});
|
||||
}
|
||||
|
||||
@ -110,12 +111,14 @@ export class DataService {
|
||||
return this.http.get<SymbolItem>(`/api/symbol/${aSymbol}`);
|
||||
}
|
||||
|
||||
public fetchPositions(): Observable<PortfolioPositions> {
|
||||
return this.http.get<PortfolioPositions>('/api/portfolio/positions').pipe(
|
||||
map((respose) => {
|
||||
return respose;
|
||||
})
|
||||
);
|
||||
public fetchPositions({
|
||||
range
|
||||
}: {
|
||||
range: DateRange;
|
||||
}): Observable<PortfolioPositions> {
|
||||
return this.http.get<PortfolioPositions>('/api/portfolio/positions', {
|
||||
params: { range }
|
||||
});
|
||||
}
|
||||
|
||||
public fetchSymbols(aQuery: string) {
|
||||
|
@ -1,12 +1,23 @@
|
||||
import {
|
||||
MarketState,
|
||||
Type
|
||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import { Currency } from '@prisma/client';
|
||||
|
||||
export interface Position {
|
||||
averagePrice: number;
|
||||
currency: Currency;
|
||||
firstBuyDate: string;
|
||||
grossPerformance?: number;
|
||||
grossPerformancePercentage?: number;
|
||||
investment: number;
|
||||
investmentInOriginalCurrency?: number;
|
||||
marketPrice?: number;
|
||||
marketState?: MarketState;
|
||||
name?: string;
|
||||
quantity: number;
|
||||
symbol: string;
|
||||
transactionCount: number;
|
||||
type?: Type;
|
||||
url?: string;
|
||||
}
|
||||
|
@ -1,7 +1,3 @@
|
||||
import {
|
||||
MarketState,
|
||||
Type
|
||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import { Currency } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
|
||||
@ -9,15 +5,11 @@ export interface TimelinePosition {
|
||||
averagePrice: Big;
|
||||
currency: Currency;
|
||||
firstBuyDate: string;
|
||||
marketState: MarketState;
|
||||
grossPerformance: Big;
|
||||
grossPerformancePercentage: Big;
|
||||
investment: Big;
|
||||
marketPrice: number;
|
||||
quantity: Big;
|
||||
symbol: string;
|
||||
investment: Big;
|
||||
grossPerformancePercentage: Big | number; // TODO
|
||||
grossPerformance: Big | number; // TODO
|
||||
marketPrice: number;
|
||||
transactionCount: number;
|
||||
name: string;
|
||||
url: string;
|
||||
type: Type;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user