Skip to content

Commit 3ef8ce6

Browse files
committed
Updated portfolio management
1 parent 7e474e9 commit 3ef8ce6

9 files changed

+150
-69
lines changed

ecosystem.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = {
55
script: "dist/app.js",
66
instances: 1,
77
exec_mode: "fork",
8-
watch: ".",
8+
watch: false
99
},
1010
],
1111
deploy: {

package-lock.json

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"ngx-bootstrap": "^4.1.1",
6666
"path": "^0.12.7",
6767
"pm2": "^5.3.0",
68-
"primeflex": "^1.0.0",
68+
"primeflex": "2.0.0",
6969
"primeicons": "^6.0.1",
7070
"primeng": "11.4.5",
7171
"qs": "^6.5.1",

src/app/machine-daytrading/machine-daytrading.service.ts

+53-42
Original file line numberDiff line numberDiff line change
@@ -37,50 +37,61 @@ export class MachineDaytradingService {
3737
}, 'MachineDaytradingService_ml', null, false, 300000);
3838
}
3939

40+
findSingleTrade(stockSymbol, stopTime = null, mainCallback = (stock, quantity, price) => { }) {
41+
if (!stockSymbol) {
42+
stockSymbol = this.getRandomStock();
43+
}
44+
this.backtestService.getDaytradeRecommendation(stockSymbol, 0, 0, { minQuotes: 81 }, 'tiingo').subscribe(
45+
analysis => {
46+
if (analysis.mfiTrade.toLowerCase() === 'bullish' || analysis.vwma.toLowerCase() === 'bullish') {
47+
this.schedulerService.schedule(() => {
48+
this.machineLearningService
49+
.trainPredictNext30(stockSymbol,
50+
moment().add({ days: 1 }).format('YYYY-MM-DD'),
51+
moment().subtract({ days: 1 }).format('YYYY-MM-DD'),
52+
1,
53+
this.globalSettingsService.daytradeAlgo
54+
)
55+
.subscribe((data: any[]) => {
56+
// if (data[0].nextOutput > 0.5 && data[0].correct / data[0].guesses > 0.5) {
57+
if (data[0].correct / data[0].guesses > 0.6 && data[0].guesses > 50) {
58+
const cb = (quantity, price) => {
59+
this.selectedStock = stockSymbol;
60+
this.quantity = quantity;
61+
this.orderSize = _.floor(quantity / 3) || 1;
62+
console.log('Set trade: ', stockSymbol, this.quantity, this.orderSize);
63+
mainCallback(stockSymbol, quantity, price);
64+
};
65+
66+
console.log('Found a trade: ', stockSymbol);
67+
68+
if (this.allocationTotal !== null && this.allocationPct !== null) {
69+
console.log('Adding trade 1: ', stockSymbol);
70+
this.addOrder('daytrade', stockSymbol, this.allocationPct, this.allocationTotal, cb, analysis.data.price);
71+
} else {
72+
this.schedulerService.schedule(() => {
73+
this.getPortfolioBalance().subscribe(balance => {
74+
console.log('Adding trade 2: ', stockSymbol);
75+
this.addOrder('daytrade', stockSymbol, 1, balance.availableFunds, cb, analysis.data.price);
76+
});
77+
}, 'MachineDaytradingService_add_order', stopTime, true);
78+
}
79+
} else {
80+
mainCallback(null, null, null);
81+
}
82+
}, () => {
83+
mainCallback(null, null, null);
84+
});
85+
}, 'MachineDaytradingService_ml', stopTime);
86+
}
87+
}
88+
);
89+
}
90+
4091
findTrade() {
4192
this.schedulerService.schedule(() => {
4293
if (!this.selectedStock) {
43-
const stock = this.getRandomStock();
44-
this.backtestService.getDaytradeRecommendation(stock, 0, 0, { minQuotes: 81 }, 'tiingo').subscribe(
45-
analysis => {
46-
if (analysis.mfiTrade.toLowerCase() === 'bullish' || analysis.vwma.toLowerCase() === 'bullish') {
47-
this.schedulerService.schedule(() => {
48-
this.machineLearningService
49-
.trainPredictNext30(stock,
50-
moment().add({ days: 1 }).format('YYYY-MM-DD'),
51-
moment().subtract({ days: 1 }).format('YYYY-MM-DD'),
52-
1,
53-
this.globalSettingsService.daytradeAlgo
54-
)
55-
.subscribe((data: any[]) => {
56-
// if (data[0].nextOutput > 0.5 && data[0].correct / data[0].guesses > 0.5) {
57-
if (data[0].correct / data[0].guesses > 0.6 && data[0].guesses > 50) {
58-
const cb = (quantity) => {
59-
this.selectedStock = stock;
60-
this.quantity = quantity;
61-
this.orderSize = _.floor(quantity / 3) || 1;
62-
console.log('Set trade: ', stock, this.quantity, this.orderSize);
63-
};
64-
65-
console.log('Found a trade: ', stock);
66-
67-
if (this.allocationTotal !== null && this.allocationPct !== null) {
68-
console.log('Adding trade 1: ', stock);
69-
this.addOrder('daytrade', stock, this.allocationPct, this.allocationTotal, cb, analysis.data.price);
70-
} else {
71-
this.schedulerService.schedule(() => {
72-
this.getPortfolioBalance().subscribe(balance => {
73-
console.log('Adding trade 2: ', stock);
74-
this.addOrder('daytrade', stock, 1, balance.availableFunds, cb, analysis.data.price);
75-
});
76-
}, 'MachineDaytradingService_add_order', this.globalSettingsService.stopTime, true);
77-
}
78-
}
79-
});
80-
}, 'MachineDaytradingService_ml', this.globalSettingsService.stopTime);
81-
}
82-
}
83-
);
94+
this.findSingleTrade(null, this.globalSettingsService.stopTime);
8495
}
8596
}, 'MachineDaytradingService_get_recommendation', this.globalSettingsService.stopTime);
8697
}
@@ -90,7 +101,7 @@ export class MachineDaytradingService {
90101
return _.floor(totalCost / stockPrice);
91102
}
92103

93-
addOrder(orderType: string, stock: string, allocationPct: number, total: number, cb: (arg1: number, arg2: number) => void, lastPrice, reject = err => {}) {
104+
addOrder(orderType: string, stock: string, allocationPct: number, total: number, cb: (arg1: number, arg2: number) => void, lastPrice, reject = err => { }) {
94105
if (orderType.toLowerCase() === 'sell') {
95106
this.portfolioService.getTdPortfolio().subscribe((data) => {
96107
data.forEach((holding) => {

src/app/portfolio-info/portfolio-info.component.html

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
<p-table [columns]="cols" [value]="holdings" [paginator]="true" [rows]="20" dataKey="name" selectionMode="single"
22
(onRowSelect)="onRowSelect($event)" [resizableColumns]="true" columnResizeMode="expand">
33
<ng-template pTemplate="caption">
4-
<div class="ui-g">
5-
<div class="ui-g-4">
6-
<h2>Portfolio Management</h2>
7-
</div>
8-
<div class="ui-g-4">
4+
<h2>Portfolio Management</h2>
5+
6+
<div class="p-d-flex">
7+
<div class="p-mr-2">
98
<app-default-order-lists class="default-orders-button" [prefillOrderForm]="prefillOrderForm">
109
</app-default-order-lists>
1110
</div>
12-
<div class="ui-g-4">
11+
<div class="p-mr-2">
1312
<button pButton type="button" icon="pi pi-refresh" iconPos="left" (click)="refresh()"></button>
1413
</div>
14+
<div class="p-mr-2">
15+
<p-inputSwitch (onChange)="setAutoControl()" [(ngModel)]="autoControl"></p-inputSwitch>
16+
<div class="control-switch">
17+
<label>Auto Control</label>
18+
</div>
19+
</div>
1520
</div>
1621
</ng-template>
1722
<ng-template pTemplate="header" let-columns>
@@ -48,6 +53,8 @@ <h2>Portfolio Management</h2>
4853
</ng-template>
4954
</p-table>
5055

56+
<app-terminal-view></app-terminal-view>
57+
5158
<app-pokerhand></app-pokerhand>
5259
<app-ai-picks></app-ai-picks>
5360

@@ -57,11 +64,9 @@ <h2>Portfolio Management</h2>
5764
</ng-template>
5865
<ng-template pTemplate="content" let-event>
5966
<p-card [header]="event.status" [subheader]="event.date">
60-
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam
61-
deserunt
62-
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!
67+
<p>
68+
{{event.message}}
6369
</p>
64-
<button pButton label="Read more" class="p-button-text"></button>
6570
</p-card>
6671
</ng-template>
6772
</p-timeline>

src/app/portfolio-info/portfolio-info.component.scss

+4
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
left: 40%;
33
position: relative;
44
}
5+
6+
.control-switch {
7+
margin-left: 1em;
8+
}

src/app/portfolio-info/portfolio-info.component.ts

+62-8
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import { SmartOrder } from '@shared/models/smart-order';
99
import { take, takeUntil } from 'rxjs/operators';
1010
import { SchedulerService } from '@shared/service/scheduler.service';
1111
import { Subject } from 'rxjs';
12-
import { PrimeIcons } from 'primeng/api';
1312
import { TimerObservable } from 'rxjs-compat/observable/TimerObservable';
1413
import { GlobalSettingsService } from '../settings/global-settings.service';
1514
import { DaytradeManagerService } from '@shared/services/daytrade-manager.service';
15+
import { MachineDaytradingService } from '../machine-daytrading/machine-daytrading.service';
1616

1717
// bearishMidTermProfitLoss: 0
1818
// bearishMidTermSignals: 0
@@ -43,9 +43,14 @@ export class PortfolioInfoComponent implements OnInit, OnDestroy {
4343
holdings: PortfolioInfoHolding[];
4444
prefillOrderForm;
4545
cols;
46-
destroy$ = new Subject();
46+
destroy$;
4747
daytradeEvents: any[] = [];
4848
simultaneousOrderLimit = 3;
49+
autoControl = false;
50+
daytradeBuffer$;
51+
buyingPower = 0;
52+
bettingScheme = [0.05, 0.1, 0.2, 0.5];
53+
bettingIndex = -1;
4954

5055
constructor(private portfolioService: PortfolioService,
5156
private backtestService: BacktestService,
@@ -55,18 +60,18 @@ export class PortfolioInfoComponent implements OnInit, OnDestroy {
5560
private schedulerService: SchedulerService,
5661
private authenticationService: AuthenticationService,
5762
private globalSettingsService: GlobalSettingsService,
58-
private daytradeManager: DaytradeManagerService) { }
63+
private daytradeManagerService: DaytradeManagerService,
64+
private machineDaytradingService: MachineDaytradingService) { }
5965

6066
ngOnInit() {
67+
this.destroy$ = new Subject();
68+
this.daytradeBuffer$ = new Subject();
6169
this.init();
6270
}
6371

6472
init() {
6573
this.daytradeEvents = [
66-
{ status: 'Ordered', date: '15/10/2020 10:30' },
67-
{ status: 'Processing', date: '15/10/2020 14:00' },
68-
{ status: 'Shipped', date: '15/10/2020 16:15' },
69-
{ status: 'Delivered', date: '16/10/2020 10:00' }
74+
{ status: 'Started', date: moment().format(), message: '' }
7075
];
7176

7277
this.aiPicksService.mlSellResults
@@ -120,6 +125,8 @@ export class PortfolioInfoComponent implements OnInit, OnDestroy {
120125
.pipe(take(1))
121126
.subscribe((balance) => {
122127
const totalValue = balance.liquidationValue;
128+
this.buyingPower = balance.buyingPower;
129+
123130
this.portfolioService.getTdPortfolio().subscribe((data) => {
124131
if (data) {
125132
data.forEach((holding) => {
@@ -159,6 +166,7 @@ export class PortfolioInfoComponent implements OnInit, OnDestroy {
159166
}
160167
});
161168
}
169+
this.findDaytrades();
162170
});
163171
});
164172
});
@@ -336,7 +344,7 @@ export class PortfolioInfoComponent implements OnInit, OnDestroy {
336344

337345
if (moment().isAfter(moment(this.globalSettingsService.startTime)) &&
338346
moment().isBefore(moment(this.globalSettingsService.stopTime))) {
339-
this.daytradeManager.executeDaytrade();
347+
this.daytradeManagerService.executeDaytrade();
340348
}
341349

342350
if (moment().isAfter(moment(this.globalSettingsService.stopTime)) &&
@@ -346,6 +354,52 @@ export class PortfolioInfoComponent implements OnInit, OnDestroy {
346354
});
347355
}
348356

357+
findDaytrades() {
358+
this.machineDaytradingService.allocationPct = this.determineMachineDaytradingPct();
359+
this.machineDaytradingService.allocationTotal = this.determineMachineDaytradingTotal();
360+
361+
const cb = (stock, quantity, price) => {
362+
if (stock && quantity && price) {
363+
const newDaytradeOrder = this.buildOrder(stock, quantity, price, 'Daytrade');
364+
this.cartService.addToCart(newDaytradeOrder);
365+
}
366+
367+
if (this.cartService.otherOrders.length < 5) {
368+
this.triggerNext();
369+
}
370+
};
371+
this.daytradeBuffer$
372+
.pipe(takeUntil(this.destroy$))
373+
.subscribe(() => {
374+
this.machineDaytradingService.findSingleTrade(null, null, cb);
375+
}, () => {
376+
cb(null, null, null);
377+
});
378+
this.triggerNext();
379+
}
380+
381+
triggerNext() {
382+
this.daytradeBuffer$.next();
383+
}
384+
385+
determineMachineDaytradingPct() {
386+
const lastProfitLoss = JSON.parse(sessionStorage.getItem('profitLoss'));
387+
if (lastProfitLoss && lastProfitLoss.profit < 0) {
388+
this.bettingIndex++;
389+
} else {
390+
this.bettingIndex = 0;
391+
}
392+
return this.bettingScheme[this.bettingIndex];
393+
}
394+
395+
determineMachineDaytradingTotal() {
396+
return this.buyingPower;
397+
}
398+
399+
setAutoControl() {
400+
this.autoControl = !this.autoControl;
401+
}
402+
349403
ngOnDestroy() {
350404
this.destroy$.next();
351405
this.destroy$.complete();

src/app/shared/services/score-keeper.service.ts

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export class ScoreKeeperService {
2323

2424
constructor(private reportingService: ReportingService) { }
2525

26+
resetTotal() {
27+
this.total = 0;
28+
}
29+
2630
addProfitLoss(stock: string, sum: number) {
2731
this.total += sum;
2832

src/app/shopping-list/shopping-list.component.ts

+3
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ export class ShoppingListComponent implements OnInit, OnDestroy {
268268
const profitLog = `Profit ${this.scoreKeeperService.total}`;
269269
this.reportingService.addAuditLog(null, profitLog);
270270
this.reportingService.exportAuditHistory();
271+
const profitObj = {'date': moment().format(), profit: this.scoreKeeperService.total};
272+
sessionStorage.setItem('profitLoss', JSON.stringify(profitObj));
273+
this.scoreKeeperService.resetTotal();
271274
}
272275
this.interval = moment().subtract(5, 'minutes').diff(moment(this.globalSettingsService.startTime), 'milliseconds');
273276
console.log('new interval: ', this.interval);

0 commit comments

Comments
 (0)