Browse Source

feat: import historical data for an assert

- new POST endpoint
pull/2448/head
Kevin Lien 2 years ago
committed by Thomas
parent
commit
e67f2c37fa
  1. 38
      apps/api/src/app/admin/admin.controller.ts
  2. 10
      apps/api/src/app/admin/update-bulk-market-data.dto.ts
  3. 6
      apps/api/src/app/admin/update-market-data.dto.ts
  4. 31
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  5. 22
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  6. 14
      apps/client/src/app/services/admin.service.ts

38
apps/api/src/app/admin/admin.controller.ts

@ -43,6 +43,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { AdminService } from './admin.service';
import { UpdateAssetProfileDto } from './update-asset-profile.dto';
import { UpdateBulkMarketDataDto } from './update-bulk-market-data.dto';
import { UpdateMarketDataDto } from './update-market-data.dto';
@Controller('admin')
@ -313,6 +314,43 @@ export class AdminController {
return this.adminService.getMarketDataBySymbol({ dataSource, symbol });
}
@UseGuards(AuthGuard('jwt'))
@Post('market-data/:dataSource/:symbol')
public async updateMarketData(
@Param('dataSource') dataSourceParam: DataSource,
@Param('symbol') symbolParam: string,
@Body() data: UpdateBulkMarketDataDto
) {
console.log('hit post new endoint nice');
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const dataBulkUpdate: Prisma.MarketDataUpdateInput[] = [];
data.marketData.forEach((entry) => {
dataBulkUpdate.push({
dataSource: dataSourceParam,
symbol: symbolParam,
date: entry.date,
marketPrice: entry.marketPrice,
state: 'CLOSE'
});
});
return this.marketDataService.updateMany({
data: dataBulkUpdate
});
}
/**
* @deprecated
*/
@Put('market-data/:dataSource/:symbol/:dateString')
@UseGuards(AuthGuard('jwt'))
public async update(

10
apps/api/src/app/admin/update-bulk-market-data.dto.ts

@ -0,0 +1,10 @@
import { ArrayNotEmpty, IsArray, isNotEmptyObject } from 'class-validator';
import { Type } from 'class-transformer';
import { UpdateMarketDataDto } from './update-market-data.dto';
export class UpdateBulkMarketDataDto {
@IsArray()
@ArrayNotEmpty()
@Type(() => UpdateMarketDataDto)
marketData: UpdateMarketDataDto[];
}

6
apps/api/src/app/admin/update-market-data.dto.ts

@ -1,6 +1,10 @@
import { IsNumber } from 'class-validator';
import { IsDate, IsNumber, IsOptional } from 'class-validator';
export class UpdateMarketDataDto {
@IsDate()
@IsOptional()
date?: Date;
@IsNumber()
marketPrice: number;
}

31
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -8,7 +8,10 @@ import {
} from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { parseISO } from 'date-fns';
import { UpdateAssetProfileDto } from '@ghostfolio/api/app/admin/update-asset-profile.dto';
import { UpdateMarketDataDto } from '@ghostfolio/api/app/admin/update-market-data.dto';
import { AdminService } from '@ghostfolio/client/services/admin.service';
import { DataService } from '@ghostfolio/client/services/data.service';
import {
@ -43,6 +46,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
[code: string]: { name: string; value: number };
};
public isBenchmark = false;
public historicalDataAsString: string;
public marketDataDetails: MarketData[] = [];
public sectors: {
[name: string]: { name: string; value: number };
@ -203,4 +207,31 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
public importHistoricalData() {
const inputHistoricalData = this.historicalDataAsString;
const inputSplittedByLine = inputHistoricalData.split('\n');
const dataBulkUpdate: UpdateMarketDataDto[] = [];
inputSplittedByLine.forEach((line) => {
const inputSplittedBySeparator = line.split(';');
const inputDate = parseISO(inputSplittedBySeparator[0]);
dataBulkUpdate.push({
date: inputDate,
marketPrice: Number(inputSplittedBySeparator[1])
});
});
this.adminService
.postMarketData({
dataSource: this.data.dataSource,
marketData: { marketData: dataBulkUpdate },
symbol: this.data.symbol
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.dataService.updateInfo();
});
this.historicalDataAsString = '';
}
}

22
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -51,6 +51,28 @@
[symbol]="data.symbol"
(marketDataChanged)="onMarketDataChanged($event)"
></gf-admin-market-data-detail>
<div class="mt-3">
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Historical Data</mat-label>
<textarea
cdkAutosizeMaxRows="5"
cdkTextareaAutosize
matInput
placeholder="e.g. 20230601;1.61"
type="text"
[ngModelOptions]="{standalone: true}"
[(ngModel)]="historicalDataAsString"
></textarea>
</mat-form-field>
</div>
<div class="d-flex justify-content-end" mat-dialog-actions>
<button color="warn" mat-flat-button (click)="importHistoricalData()">
<ng-container i18n>Import historical Data </ng-container>
</button>
</div>
<div class="row">
<div class="col-6 mb-3">
<gf-value i18n size="medium" [value]="assetProfile?.symbol"

14
apps/client/src/app/services/admin.service.ts

@ -1,6 +1,7 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { UpdateAssetProfileDto } from '@ghostfolio/api/app/admin/update-asset-profile.dto';
import { UpdateBulkMarketDataDto } from '@ghostfolio/api/app/admin/update-bulk-market-data.dto';
import { UpdateMarketDataDto } from '@ghostfolio/api/app/admin/update-market-data.dto';
import { CreatePlatformDto } from '@ghostfolio/api/app/platform/create-platform.dto';
import { UpdatePlatformDto } from '@ghostfolio/api/app/platform/update-platform.dto';
@ -214,6 +215,19 @@ export class AdminService {
);
}
public postMarketData({
dataSource,
marketData,
symbol
}: {
dataSource: DataSource;
marketData: UpdateBulkMarketDataDto;
symbol: string;
}) {
const url = `/api/v1/admin/market-data/${dataSource}/${symbol}`;
return this.http.post<MarketData>(url, marketData);
}
public postPlatform(aPlatform: CreatePlatformDto) {
return this.http.post<Platform>(`/api/v1/platform`, aPlatform);
}

Loading…
Cancel
Save