-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
605 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<script setup lang="ts"> | ||
import {LockClosedIcon} from "@heroicons/vue/24/outline"; | ||
import helpers from "../../helpers"; | ||
import {ClosedDealsGroup} from "@/types/analytics"; | ||
function formatProfit(asset: { profit: number; currency: string; }) { | ||
return (asset.profit > 0 ? '+' : '-') + ' ' + helpers.formatPrice(Math.abs(asset.profit)) + ' ' + asset.currency; | ||
} | ||
const emits = defineEmits<{ showChildren: [] }>() | ||
defineProps<{ | ||
item: ClosedDealsGroup | ||
}>(); | ||
</script> | ||
|
||
<template> | ||
<tr | ||
class="tr-clickable" | ||
@click="emits('showChildren')" | ||
> | ||
<td class="underline"> | ||
<div class="font-extrabold"> | ||
<lock-closed-icon | ||
v-if="item.isBlocked" | ||
class="h-3 w-3 inline-block" | ||
/> | ||
{{ item.shortName }} | ||
</div> | ||
<div class="text-gray-500"> | ||
<span class="text-xs">{{ item.ticker }}</span> | ||
<span | ||
v-if="item.isShort" | ||
class="bg-red-200 text-red-900 rounded-full inline-flex pr-2 pl-2 items-center ml-2" | ||
>short</span> | ||
</div> | ||
</td> | ||
<td>{{ item.quantity }}</td> | ||
<td> | ||
<div>{{ helpers.formatPrice(item.buyPrice) }} {{ item.currency }}</div> | ||
<div class="text-xs text-gray-500"> | ||
{{ helpers.formatPrice(item.fullBuyPrice) }} {{ item.currency }} | ||
</div> | ||
</td> | ||
<td> | ||
<div>{{ helpers.formatPrice(item.sellPrice) }} {{ item.currency }}</div> | ||
<div class="text-xs text-gray-500"> | ||
{{ helpers.formatPrice(item.fullSellPrice) }} {{ item.currency }} | ||
</div> | ||
</td> | ||
<td :class="[item.profit > 0 ? 'text-green-600' : 'text-red-700']"> | ||
<div>{{ formatProfit(item) }}</div> | ||
<div class="text-xs"> | ||
({{ item.profitPercent }}%, {{ item.commission }} {{ item.currency }}) | ||
</div> | ||
</td> | ||
</tr> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<script setup lang="ts"> | ||
import {LockClosedIcon} from "@heroicons/vue/24/outline"; | ||
import helpers from "../../helpers"; | ||
import {ClosedDeal} from "@/types/analytics"; | ||
function formatProfit(asset: { profit: number; currency: string; }) { | ||
return (asset.profit > 0 ? '+' : '-') + ' ' + helpers.formatPrice(Math.abs(asset.profit)) + ' ' + asset.currency; | ||
} | ||
defineProps<{ | ||
item: ClosedDeal, | ||
}>(); | ||
</script> | ||
|
||
<template> | ||
<tr> | ||
<td v-tooltip="{html: true, content: 'Created At: ' + item.createdAt + '<br>Updated At: ' + item.createdAt}"> | ||
<div class="font-extrabold"> | ||
<lock-closed-icon | ||
v-if="item.isBlocked" | ||
class="h-3 w-3 inline-block" | ||
/> | ||
{{ item.shortName }} | ||
</div> | ||
<div class="text-gray-500"> | ||
<span class="text-xs">{{ item.ticker }}</span> | ||
<span | ||
v-if="item.isShort" | ||
class="bg-red-200 text-red-900 rounded-full inline-flex pr-2 pl-2 items-center ml-2" | ||
>short</span> | ||
</div> | ||
</td> | ||
<td>{{ item.quantity }}</td> | ||
<td> | ||
<div>{{ helpers.formatPrice(item.buyPrice) }} {{ item.currency }}</div> | ||
<div class="text-xs text-gray-500"> | ||
{{ helpers.formatPrice(item.fullBuyPrice) }} {{ item.currency }} | ||
</div> | ||
</td> | ||
<td> | ||
<div>{{ helpers.formatPrice(item.sellPrice) }} {{ item.currency }}</div> | ||
<div class="text-xs text-gray-500"> | ||
{{ helpers.formatPrice(item.fullSellPrice) }} {{ item.currency }} | ||
</div> | ||
</td> | ||
|
||
<td :class="[item.profit > 0 ? 'text-green-600' : 'text-red-700']"> | ||
<div>{{ formatProfit(item) }}</div> | ||
<div class="text-xs"> | ||
({{ item.profitPercent }}%, {{ item.commission }} {{ item.currency }}) | ||
</div> | ||
</td> | ||
</tr> | ||
</template> |
111 changes: 111 additions & 0 deletions
111
assets/components/Analytics/ClosedDealsTableComponent.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<script setup lang="ts"> | ||
import {useDealsGroup} from "@/composable/useDealsGroup"; | ||
import ClosedDealsGroupComponent from "@/components/Analytics/ClosedDealsGroupComponent.vue"; | ||
import ClosedDealsItemComponent from "@/components/Analytics/ClosedDealsItemComponent.vue"; | ||
import {ClosedDealsListItem} from "@/types/analytics"; | ||
defineProps<{ assets: ClosedDealsListItem[] }>() | ||
const dealsGroup = useDealsGroup() | ||
</script> | ||
|
||
<template> | ||
<table class="simple-table sub-table white-header"> | ||
<thead> | ||
<tr> | ||
<th>Name</th> | ||
<th>Quantity</th> | ||
<th>Buy Price</th> | ||
<th>Sell Price</th> | ||
<th> | ||
Profit | ||
<div class="text-xs text-gray-400"> | ||
(percent, commission) | ||
</div> | ||
</th> | ||
</tr> | ||
</thead> | ||
|
||
<tbody> | ||
<template | ||
v-for="(asset, i) in assets" | ||
:key="i" | ||
> | ||
<!-- Asset block --> | ||
<!-- Parent row with assets --> | ||
<closed-deals-group-component | ||
:item="asset.groupData" | ||
:clickable="true" | ||
@show-children="dealsGroup.toggleGroup(asset.groupData.ticker)" | ||
/> | ||
|
||
<!-- Children table --> | ||
<tr v-if="dealsGroup.openedGroups.value[asset.groupData.ticker]"> | ||
<td | ||
colspan="111" | ||
class="!p-2 !bg-white" | ||
> | ||
<table class="simple-table sub-table white-header"> | ||
<thead> | ||
<tr> | ||
<th>Name</th> | ||
<th>Quantity</th> | ||
<th>Buy Price</th> | ||
<th>Sell Price</th> | ||
<th> | ||
Profit | ||
<div class="text-xs text-gray-400"> | ||
(percent, commission) | ||
</div> | ||
</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<template | ||
v-for="(subItem, subIndex) in asset.deals" | ||
:key="'sub' + subIndex" | ||
> | ||
<closed-deals-item-component :item="subItem" /> | ||
</template> | ||
</tbody> | ||
</table> | ||
</td> | ||
</tr> | ||
</template> | ||
|
||
<!-- Total row --> | ||
<!-- <tr class="font-bold"> | ||
<td>Subtotal:</td> | ||
<td /> | ||
<td> | ||
<div v-if="!summary.isBaseCurrency"> | ||
{{ helpers.formatPrice(summary.buyPrice) }} $ | ||
</div> | ||
<div>{{ helpers.formatPrice(summary.buyPriceInBaseCurrency) }} ₽</div> | ||
</td> | ||
<td> | ||
<div v-if="!summary.isBaseCurrency"> | ||
{{ helpers.formatPrice(summary.currentPrice) }} $ | ||
</div> | ||
<div>{{ helpers.formatPrice(summary.currentPriceInBaseCurrency) }} ₽</div> | ||
</td> | ||
<td /> | ||
<td :class="[summary.profit > 0 ? 'text-green-600' : 'text-red-700']"> | ||
<div v-if="!summary.isBaseCurrency"> | ||
{{ helpers.formatPrice(summary.profit) }} $ | ||
</div> | ||
<div>{{ helpers.formatPrice(summary.profitInBaseCurrency) }} ₽</div> | ||
<div class="text-xs"> | ||
({{ summary.profitPercent }}%) | ||
</div> | ||
</td> | ||
<td /> | ||
<td /> | ||
<td class="table-actions" /> | ||
</tr>--> | ||
</tbody> | ||
</table> | ||
</template> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,16 @@ | ||
import {ref} from "vue"; | ||
import {AssetsGroup} from "@/types/account"; | ||
import axios from "axios"; | ||
import useAsync from "@/utils/use-async"; | ||
import {ClosedDealsListItem} from "@/types/analytics"; | ||
|
||
const assets = ref<AssetsGroup[]>([]) | ||
const closedDeals = ref<{deals: ClosedDealsListItem[]}>() | ||
|
||
export default function () { | ||
async function getAssets() { | ||
assets.value = await axios.get('/api/analytics').then((response) => response.data); | ||
async function getClosedDeals() { | ||
closedDeals.value = await axios.get('/api/analytics/closed-deals').then((response) => response.data); | ||
} | ||
|
||
const {loading, run: asyncGetAssets} = useAsync(getAssets) | ||
|
||
return { | ||
assets, | ||
loading, | ||
getAssets: asyncGetAssets | ||
getClosedDeals, | ||
closedDeals | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<script setup lang="ts"> | ||
import PageComponent from "../../components/PageComponent.vue"; | ||
import useAnalytics from "@/composable/useAnalytics"; | ||
import useAsync from "@/utils/use-async"; | ||
import PreloaderComponent from "@/components/Common/PreloaderComponent.vue"; | ||
import ClosedDealsTableComponent from "@/components/Analytics/ClosedDealsTableComponent.vue"; | ||
const {closedDeals, getClosedDeals} = useAnalytics() | ||
const {loading, run} = useAsync(() => getClosedDeals()) | ||
run() | ||
</script> | ||
|
||
<template> | ||
<page-component title="Closed Deals"> | ||
<preloader-component v-if="loading" /> | ||
<div v-else-if="closedDeals"> | ||
<closed-deals-table-component :assets="closedDeals.deals" /> | ||
</div> | ||
</page-component> | ||
</template> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
export interface ClosedDealsListItem { | ||
groupData: ClosedDealsGroup | ||
deals: ClosedDeal[] | ||
} | ||
|
||
export interface ClosedDealsGroup { | ||
ticker: string | ||
shortName: string | ||
quantity: number | ||
buyPrice: number | ||
fullBuyPrice: number | ||
sellPrice: number | ||
fullSellPrice: number | ||
profit: number | ||
profitPercent: number | ||
commission: number | ||
currency: string | ||
isShort: boolean | ||
isBlocked: boolean | ||
} | ||
|
||
export interface ClosedDeal { | ||
id: number | ||
accountId: number | ||
ticker: string | ||
shortName: string | ||
quantity: number | ||
buyPrice: number | ||
fullBuyPrice: number | ||
sellPrice: number | ||
fullSellPrice: number | ||
profit: number | ||
profitPercent: number | ||
commission: number | ||
currency: string | ||
isShort: boolean | ||
isBlocked: boolean | ||
createdAt: string | ||
updatedAt: string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Controller; | ||
|
||
use App\Entity\User; | ||
use App\Request\DTO\Deals\DealsFilterRequestDTO; | ||
use App\Services\Deals\ClosedDealsService; | ||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
use Symfony\Component\HttpKernel\Attribute\MapQueryString; | ||
use Symfony\Component\Routing\Annotation\Route; | ||
use Symfony\Component\Security\Http\Attribute\CurrentUser; | ||
|
||
class AnalyticsController extends AbstractController | ||
{ | ||
#[Route('/analytics/closed-deals', name: 'app_analytics_closed_deals', methods: 'GET')] | ||
public function closedDeals( | ||
ClosedDealsService $dealsService, | ||
#[MapQueryString] ?DealsFilterRequestDTO $filter, | ||
#[CurrentUser] ?User $user, | ||
): JsonResponse { | ||
$deals = $dealsService->getDeals($user, $filter); | ||
return $this->json(['deals' => $deals]); | ||
} | ||
} |
Oops, something went wrong.