Skip to content

Commit ff7898e

Browse files
committed
updated code with liquidation, stoploss
1 parent 580cbec commit ff7898e

File tree

22 files changed

+1162
-456
lines changed

22 files changed

+1162
-456
lines changed

.github/workflows/deploy.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Deploy to GCP VM
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
deploy:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout repo
15+
uses: actions/checkout@v4
16+
17+
- name: Authenticate with Google Cloud
18+
uses: google-github-actions/auth@v2
19+
with:
20+
credentials_json: ${{ secrets.GCP_SA_KEY }}
21+
22+
- name: Set up gcloud
23+
uses: google-github-actions/setup-gcloud@v2
24+
with:
25+
project_id: ${{ secrets.GCP_PROJECT }}
26+
27+
- name: Start VM (if stopped)
28+
run: |
29+
gcloud compute instances start ${{ secrets.GCP_VM_NAME }} \
30+
--zone=${{ secrets.GCP_VM_ZONE }}
31+
32+
- name: Run commands on VM
33+
run: |
34+
gcloud compute ssh ${{ secrets.GCP_VM_NAME }} \
35+
--zone=${{ secrets.GCP_VM_ZONE }} \
36+
--command "
37+
rm -rf exness &&
38+
git clone https://github.com/${{ github.repository }} repo &&
39+
cd repo &&
40+
docker compose build --no-cache &&
41+
docker compose up -d
42+
"
43+
44+
- name: Stop VM (optional)
45+
if: always()
46+
run: |
47+
gcloud compute instances stop ${{ secrets.GCP_VM_NAME }} \
48+
--zone=${{ secrets.GCP_VM_ZONE }}

frontend/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import Signup from "./pages/Signup";
55
import Trading from "./pages/Trading";
66
import Navbar from "./components/Navbar";
77
import "aos/dist/aos.css";
8-
import Landing from "./pages/Homepage";
8+
import ExnessLanding from "./pages/Homepage";
99

1010
function App() {
1111
return (
1212
<div className="min-h-screen bg-[#0c1418] text-white">
1313
<BrowserRouter>
1414
<Routes>
15-
<Route path="/" element={<Landing />} />
15+
<Route path="/" element={<ExnessLanding />} />
1616
<Route path="/signin" element={<Signin />} />
1717
<Route path="/signup" element={<Signup />} />
1818
<Route

frontend/src/api/trade.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export async function getopentrades(token: string) {
110110

111111
export async function getclosedtrades(token: string) {
112112
try {
113-
const data = await axios.get(`${BASE_URL}/trades `, {
113+
const data = await axios.get(`${BASE_URL}/trades`, {
114114
headers: {
115115
Authorization: token,
116116
},

frontend/src/components/AskBidsTable.tsx

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useEffect, useState } from "react";
2-
import { Signalingmanager } from "../utils/subscription_manager";
3-
import { Channels, type SYMBOL } from "../utils/constants";
2+
import { type SYMBOL } from "../utils/constants";
43
import { toDisplayPrice } from "../utils/utils";
4+
import { subscribePrices, type LivePrices } from "../utils/price_store";
55

66
export interface Trade {
77
buyPrice: number;
@@ -35,26 +35,14 @@ export default function AskBids({ symbol }: { symbol?: SYMBOL }) {
3535
});
3636

3737
useEffect(() => {
38-
const signalingManager = Signalingmanager.getInstance();
39-
40-
const callback = (trade: Trade) => {
41-
setBidsAsks((prev) => ({
42-
...prev,
43-
[trade.symbol]: {
44-
bids: toDisplayPrice(trade?.buyPrice),
45-
asks: toDisplayPrice(trade?.sellPrice),
46-
symbol: trade?.symbol,
47-
},
48-
}));
49-
};
50-
51-
const unwatchFunctions = Object.values(Channels).map((ch) =>
52-
signalingManager.watch(ch, callback)
53-
);
54-
55-
return () => {
56-
unwatchFunctions.forEach((unwatch) => unwatch());
57-
};
38+
const unsubscribe = subscribePrices((prices: LivePrices) => {
39+
setBidsAsks({
40+
BTC: { bids: toDisplayPrice(prices.BTC.ask), asks: toDisplayPrice(prices.BTC.bid), symbol: "BTC" },
41+
ETH: { bids: toDisplayPrice(prices.ETH.ask), asks: toDisplayPrice(prices.ETH.bid), symbol: "ETH" },
42+
SOL: { bids: toDisplayPrice(prices.SOL.ask), asks: toDisplayPrice(prices.SOL.bid), symbol: "SOL" },
43+
});
44+
});
45+
return () => unsubscribe();
5846
}, []);
5947

6048
return (
@@ -84,12 +72,12 @@ export default function AskBids({ symbol }: { symbol?: SYMBOL }) {
8472
{item.symbol}
8573
<span className="text-xs text-white/50 ml-1">USDT</span>
8674
</th>
87-
<td className="py-3 text-right font-mono text-[#EB483F]">
88-
{item.asks}
89-
</td>
9075
<td className="py-3 text-right font-mono text-[#158BF9]">
9176
{item.bids}
9277
</td>
78+
<td className="py-3 text-right font-mono text-[#EB483F]">
79+
{item.asks}
80+
</td>
9381
</tr>
9482
))}
9583
</tbody>

frontend/src/components/BuySell.tsx

Lines changed: 93 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
"use client";
22

3-
import { useState, useEffect } from "react";
3+
import { useState, useEffect, useMemo } from "react";
44
import axios from "axios";
55
import type { SYMBOL } from "../utils/constants";
66
import { createTrade, findUserAmount } from "../api/trade";
77
import { getAssetDetails } from "../api/trade";
88
import type { Asset } from "../types/asset";
9-
import { toDisplayPriceUSD } from "../utils/utils";
9+
import {
10+
calculatePnlCents,
11+
toDisplayPriceUSD,
12+
toInternalPrice,
13+
} from "../utils/utils";
1014

1115
export default function BuySell({
1216
buyPrice,
@@ -69,6 +73,48 @@ export default function BuySell({
6973
};
7074
}, [symbol]);
7175

76+
const estimatedTpPnlInCents = useMemo(() => {
77+
if (!tpEnabled || !tpPrice || Number(tpPrice) <= 0) return 0;
78+
79+
// 1. Convert all inputs to the correct scaled-integer format
80+
const openPriceForCalc =
81+
activeTab === "buy"
82+
? toInternalPrice(buyPrice)
83+
: toInternalPrice(sellPrice);
84+
const closePriceForCalc = toInternalPrice(Number(tpPrice));
85+
const marginForCalc = margin * 100; // Convert dollar margin to cents
86+
87+
// 2. Call the exact same robust function used everywhere else
88+
return calculatePnlCents({
89+
side: activeTab,
90+
openPrice: openPriceForCalc,
91+
closePrice: closePriceForCalc,
92+
marginCents: marginForCalc,
93+
leverage: leverage,
94+
});
95+
}, [tpEnabled, tpPrice, activeTab, buyPrice, sellPrice, margin, leverage]);
96+
97+
const estimatedSlPnlInCents = useMemo(() => {
98+
if (!slEnabled || !slPrice || Number(slPrice) <= 0) return 0;
99+
100+
// 1. Convert all inputs to the correct scaled-integer format
101+
const openPriceForCalc =
102+
activeTab === "buy"
103+
? toInternalPrice(buyPrice)
104+
: toInternalPrice(sellPrice);
105+
const closePriceForCalc = toInternalPrice(Number(slPrice));
106+
const marginForCalc = margin * 100; // Convert dollar margin to cents
107+
108+
// 2. Call the robust P&L function
109+
return calculatePnlCents({
110+
side: activeTab,
111+
openPrice: openPriceForCalc,
112+
closePrice: closePriceForCalc,
113+
marginCents: marginForCalc,
114+
leverage: leverage,
115+
});
116+
}, [slEnabled, slPrice, activeTab, buyPrice, sellPrice, margin, leverage]);
117+
72118
const handleSubmitTrade = async () => {
73119
if (margin <= 0) {
74120
setError("Margin must be greater than 0");
@@ -197,7 +243,7 @@ export default function BuySell({
197243
</div>
198244
<div className="mt-1 text-base font-semibold text-[#EB483F] flex items-center">
199245
<span className="text-xs mr-1">$</span>
200-
{buyPrice}
246+
{sellPrice}
201247
</div>
202248
<div className="absolute w-1 h-full bg-[#EB483F]/40 left-0 top-0"></div>
203249
</div>
@@ -210,7 +256,7 @@ export default function BuySell({
210256
</div>
211257
<div className="mt-1 text-base font-semibold text-[#158BF9] flex items-center">
212258
<span className="text-xs mr-1">$</span>
213-
{sellPrice}
259+
{buyPrice}
214260
</div>
215261
<div className="absolute w-1 h-full bg-[#158BF9]/40 left-0 top-0"></div>
216262
</div>
@@ -491,20 +537,29 @@ export default function BuySell({
491537
</div>
492538

493539
{tpEnabled && (
494-
<div className="mt-1.5 flex items-center justify-between">
495-
<div className="flex items-center gap-1">
496-
<div className="text-[10px] text-white/50">Est. Profit:</div>
540+
<div className="mt-1.5 space-y-1">
541+
<div className="flex items-center justify-between">
542+
<div className="flex items-center gap-1">
543+
<div className="text-[10px] text-white/50">
544+
Est. Profit:
545+
</div>
546+
</div>
547+
<div
548+
className={`text-[10px] px-1.5 py-0.5 rounded ${
549+
estimatedTpPnlInCents > 0
550+
? "text-green-400 bg-green-500/10"
551+
: "text-red-400 bg-red-500/10"
552+
}`}
553+
>
554+
{estimatedTpPnlInCents >= 0 ? "+$" : "-$"}
555+
{toDisplayPriceUSD(Math.abs(estimatedTpPnlInCents)).toFixed(
556+
2
557+
)}
558+
</div>
497559
</div>
498-
<div className="text-[10px] text-green-400 bg-green-500/10 px-1.5 py-0.5 rounded">
499-
+$
500-
{tpPrice
501-
? (
502-
(Number(tpPrice) -
503-
(activeTab === "buy" ? sellPrice : buyPrice)) *
504-
margin *
505-
leverage
506-
).toFixed(2)
507-
: "0.00"}
560+
<div className="text-[10px] text-white/40">
561+
Target: ${tpPrice} | Current: $
562+
{activeTab === "buy" ? buyPrice : sellPrice}
508563
</div>
509564
</div>
510565
)}
@@ -574,22 +629,28 @@ export default function BuySell({
574629
</div>
575630

576631
{slEnabled && (
577-
<div className="mt-1.5 flex items-center justify-between">
578-
<div className="flex items-center gap-1">
579-
<div className="text-[10px] text-white/50">Est. Loss:</div>
632+
<div className="mt-1.5 space-y-1">
633+
<div className="flex items-center justify-between">
634+
<div className="flex items-center gap-1">
635+
<div className="text-[10px] text-white/50">Est. Loss:</div>
636+
</div>
637+
<div
638+
className={`text-[10px] px-1.5 py-0.5 rounded ${
639+
estimatedSlPnlInCents < 0
640+
? "text-red-400 bg-red-500/10"
641+
: "text-green-400 bg-green-500/10"
642+
}`}
643+
>
644+
{/* Always show loss as negative, but use abs for the number */}
645+
{estimatedSlPnlInCents > 0 ? "+$" : "-$"}
646+
{toDisplayPriceUSD(Math.abs(estimatedSlPnlInCents)).toFixed(
647+
2
648+
)}
649+
</div>
580650
</div>
581-
<div className="text-[10px] text-red-400 bg-red-500/10 px-1.5 py-0.5 rounded">
582-
-$
583-
{slPrice
584-
? (
585-
Math.abs(
586-
Number(slPrice) -
587-
(activeTab === "buy" ? sellPrice : buyPrice)
588-
) *
589-
margin *
590-
leverage
591-
).toFixed(2)
592-
: "0.00"}
651+
<div className="text-[10px] text-white/40">
652+
Stop: ${slPrice} | Current: $
653+
{activeTab === "buy" ? buyPrice : sellPrice}
593654
</div>
594655
</div>
595656
)}

frontend/src/components/Navbar.tsx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,10 @@ export default function Navbar() {
55
<div className="flex items-center">
66
<h1 className="text-xl font-bold text-[#158BF9] mr-4 lg:mr-8">EXNESSS</h1>
77
<div className="hidden md:flex space-x-4 lg:space-x-6">
8-
<a href="/" className="text-white hover:text-[#158BF9] transition">Home</a>
9-
<a href="/trading" className="text-[#158BF9] font-medium">Trading</a>
10-
<a href="/markets" className="text-white/80 hover:text-[#158BF9] transition">Markets</a>
11-
<a href="/wallet" className="text-white/80 hover:text-[#158BF9] transition">Wallet</a>
128
</div>
139
</div>
1410

1511
<div className="flex items-center space-x-2 lg:space-x-4">
16-
d <button className="text-white/80 hover:text-white p-1.5 rounded-full bg-[#1c2a31] hover:bg-[#263136] transition">
17-
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 md:h-5 md:w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
18-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
19-
</svg>
20-
</button>
21-
<div className="bg-[#1c2a31] text-white px-2 py-1.5 rounded-md border border-[#263136] flex items-center">
22-
<span className="text-xs text-green-400 mr-1"></span>
23-
<span className="text-xs md:text-sm whitespace-nowrap">1,250.00 USD</span>
24-
</div>
25-
<button className="bg-[#158BF9] hover:bg-[#1070d8] text-white px-2 md:px-4 py-1.5 rounded-md text-xs md:text-sm font-medium transition-colors whitespace-nowrap">
26-
Deposit
27-
</button>
2812
</div>
2913
</div>
3014
</nav>

0 commit comments

Comments
 (0)