-
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.
✨🎉 Overhaul codebase & implement account selection
- Loading branch information
1 parent
84c1bc8
commit 7fce4eb
Showing
14 changed files
with
746 additions
and
9 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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,52 @@ | ||
import { redirect, type Handle } from '@sveltejs/kit'; | ||
import type { CapitalComUserAccounts } from "$lib/types" | ||
import { UserCST, UserXSecurityToken } from "$lib/stores"; | ||
|
||
let userCST: string; | ||
UserCST.subscribe((value: string) => { | ||
userCST = value; | ||
}); | ||
|
||
let userXSecurityToken: string; | ||
UserXSecurityToken.subscribe((value: string) => { | ||
userXSecurityToken = value; | ||
}); | ||
|
||
export const handle: Handle = (async ({ event, resolve }) => { | ||
if (event.url.pathname.startsWith("/dashboard") || event.url.pathname.startsWith("/api") || event.url.pathname === "/") { | ||
const capitalComCST = event.cookies.get("CAPITALCOM-CST"); | ||
const capitalComSecurityToken = event.cookies.get("CAPITALCOM-X-SECURITY-TOKEN"); | ||
|
||
if(capitalComCST === undefined || capitalComSecurityToken === undefined) { | ||
throw redirect(302, "/login"); | ||
} | ||
const response: Response = await fetch("https://api-capital.backend-capital.com/api/v1/accounts", { | ||
method: "GET", | ||
headers: { | ||
"X-SECURITY-TOKEN": capitalComSecurityToken!, | ||
"CST" : capitalComCST!, | ||
"Content-Type" : "application/json" | ||
}, | ||
redirect: "follow" | ||
}); | ||
|
||
let parsedResponse: CapitalComUserAccounts = await response.json(); | ||
|
||
if(parsedResponse.errorCode !== undefined) { | ||
throw redirect(302, "/login"); | ||
} | ||
|
||
if(parsedResponse.errorCode === undefined && capitalComCST !== userCST || parsedResponse.errorCode === undefined && capitalComSecurityToken !== userXSecurityToken) { | ||
UserCST.set(capitalComCST); | ||
UserXSecurityToken.set(capitalComSecurityToken); | ||
} | ||
|
||
if(event.url.pathname === "/") { | ||
throw redirect(303, "/dashboard"); | ||
} | ||
} | ||
|
||
const response = await resolve(event); | ||
return response; | ||
|
||
}); |
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,4 @@ | ||
import { writable, type Writable } from "svelte/store"; | ||
|
||
export const UserCST: Writable<string> = writable(""); | ||
export const UserXSecurityToken: Writable<string> = writable(""); |
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,122 @@ | ||
export interface CapitalComCreateSessionResponse { | ||
accountType?: string; | ||
accountInfo?: AccountInfo; | ||
currencyIsoCode?: string; | ||
currencySymbol?: string; | ||
currentAccountId?: string; | ||
streamingHost?: string; | ||
accounts?: (Account)[]; | ||
clientId?: string; | ||
timezoneOffset?: number; | ||
hasActiveDemoAccounts?: boolean; | ||
hasActiveLiveAccounts?: boolean; | ||
trailingStopsEnabled?: boolean; | ||
errorCode?: string; | ||
} | ||
|
||
export interface AccountInfo { | ||
balance: number; | ||
deposit: number; | ||
profitLoss: number; | ||
available: number; | ||
} | ||
|
||
export interface Account { | ||
accountId: string; | ||
accountName: string; | ||
preferred: boolean; | ||
accountType: string; | ||
} | ||
|
||
export interface CapitalComTradeHistoryResponse { | ||
activities?: Activity[]; | ||
errorCode?: string; | ||
} | ||
|
||
export interface Activity { | ||
date: string | ||
dateUTC: string | ||
epic: string | ||
dealId: string | ||
source: string | ||
type: string | ||
status: string | ||
} | ||
|
||
|
||
export interface CapitalComTradeDetailsResponse { | ||
position?: Position; | ||
market?: Market; | ||
errorCode?: string; | ||
} | ||
|
||
export interface Position { | ||
contractSize: number; | ||
createdDate: string; | ||
createdDateUTC: string; | ||
dealId: string; | ||
dealReference: string; | ||
workingOrderId: string; | ||
size: number; | ||
leverage: number; | ||
upl: number; | ||
direction: "BUY" | "SELL"; | ||
level: number; | ||
currency: string; | ||
guaranteedStop: boolean; | ||
} | ||
|
||
export interface Market { | ||
instrumentName: string; | ||
expiry: string; | ||
marketStatus: string; | ||
epic: string; | ||
instrumentType: string; | ||
lotSize: number; | ||
high: number; | ||
low: number; | ||
percentageChange: number; | ||
netChange: number; | ||
bid: number; | ||
offer: number; | ||
updateTime: string; | ||
updateTimeUTC: string; | ||
delayTime: number; | ||
streamingPricesAvailable: boolean; | ||
scalingFactor: number; | ||
} | ||
|
||
export interface CapitalComPingResponse { | ||
status?: "ok" | string, | ||
errorCode?: string | ||
} | ||
|
||
export interface CapitalComUserAccounts { | ||
accounts?: Account[]; | ||
errorCode?: string | ||
} | ||
|
||
export interface Account { | ||
accountId: string | ||
accountName: string | ||
status: string | ||
accountType: string | ||
preferred: boolean | ||
balance: Balance | ||
currency: string | ||
} | ||
|
||
export interface Balance { | ||
balance: number | ||
deposit: number | ||
profitLoss: number | ||
available: number | ||
} | ||
|
||
export interface SwitchAccountsResponse { | ||
trailingStopsEnabled?: boolean | ||
dealingEnabled?: boolean | ||
hasActiveDemoAccounts?: boolean | ||
hasActiveLiveAccounts?: boolean | ||
errorCode?: 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,31 @@ | ||
<script lang="ts"> | ||
import { page } from "$app/stores"; | ||
import type { CapitalComPingResponse } from "$lib/types" | ||
import { UserCST, UserXSecurityToken } from "$lib/stores"; | ||
import "../app.postcss"; | ||
import { redirect } from "@sveltejs/kit"; | ||
import { Toaster } from "svelte-french-toast"; | ||
if($page.route.id?.startsWith("/dashboard")) { | ||
setInterval(async () => { | ||
const response: Response = await fetch("https://api-capital.backend-capital.com/api/v1/ping", { | ||
method: "GET", | ||
headers: { | ||
"X-SECURITY-TOKEN": $UserXSecurityToken.toString(), | ||
"CST" : $UserCST.toString(), | ||
"Content-Type" : "application/json" | ||
}, | ||
redirect: "follow" | ||
}); | ||
let parsedResponse: CapitalComPingResponse = await response.json(); | ||
if(parsedResponse.errorCode !== undefined) { | ||
throw redirect(302, "/login"); | ||
} | ||
}, 580000) | ||
} | ||
</script> | ||
|
||
<Toaster/> | ||
<slot /> |
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,58 @@ | ||
import { json, redirect, type RequestHandler } from '@sveltejs/kit'; | ||
import type { CapitalComTradeDetailsResponse, CapitalComTradeHistoryResponse } from "$lib/types"; | ||
import { UserCST, UserXSecurityToken } from "$lib/stores"; | ||
|
||
let userCST: string; | ||
UserCST.subscribe((value: string) => { | ||
userCST = value; | ||
}); | ||
|
||
let userXSecurityToken: string; | ||
UserXSecurityToken.subscribe((value: string) => { | ||
userXSecurityToken = value; | ||
}); | ||
|
||
|
||
export const GET = (async ({ cookies }) => { | ||
const capitalComCST = cookies.get("CAPITALCOM-CST"); | ||
const capitalComSecurityToken = cookies.get("CAPITALCOM-X-SECURITY-TOKEN"); | ||
if(userCST !== capitalComCST || userXSecurityToken !== capitalComSecurityToken) { throw redirect(302, "/login") } | ||
const response: Response = await fetch("https://api-capital.backend-capital.com/api/v1/history/activity?type=POSITION&lastPeriod=86400", { | ||
method: "GET", | ||
headers: { | ||
"X-SECURITY-TOKEN": userXSecurityToken, | ||
"CST": userCST, | ||
"Content-Type" : "application/json" | ||
} | ||
}); | ||
|
||
const parsedResponse: CapitalComTradeHistoryResponse = await response.json(); | ||
if(parsedResponse.errorCode !== undefined) { return json([{ error: parsedResponse.errorCode }]); } | ||
let tradeArrayToReturn: Array<{ title?: string; description?: string; error?: string }> = []; | ||
|
||
await Promise.all(parsedResponse.activities!.map(async trade => { | ||
if(trade.source === "USER" && trade.type === "POSITION") { | ||
const tradeDetailsResponse: Response = await fetch(`https://api-capital.backend-capital.com/api/v1/positions/${trade.dealId}`, { | ||
method: "GET", | ||
headers: { | ||
"X-SECURITY-TOKEN": userXSecurityToken, | ||
"CST": userCST, | ||
"Content-Type" : "application/json" | ||
} | ||
}); | ||
|
||
const parsedTradeDetailsResponse: CapitalComTradeDetailsResponse = await tradeDetailsResponse.json(); | ||
console.log(parsedTradeDetailsResponse); | ||
if(parsedTradeDetailsResponse.errorCode === undefined) { | ||
tradeArrayToReturn.push({ | ||
title: `${parsedTradeDetailsResponse.position!.direction! === "BUY" ? "Bought" : "Sold"} ${parsedTradeDetailsResponse.position!.size!} ${parsedTradeDetailsResponse!.market?.instrumentType.toLowerCase()} of ${parsedTradeDetailsResponse.market!.instrumentName}`, | ||
description: `${new Date(new Date().getTime() - new Date(parsedTradeDetailsResponse.position!.createdDate).getTime()).getMinutes()} ${(new Date(new Date().getTime() - new Date(parsedTradeDetailsResponse.position!.createdDate).getTime()).getMinutes()) === 1 ? "minute" : "minutes"} ago` | ||
}) | ||
} else { | ||
console.log(`Error when getting details of one trade: ${parsedTradeDetailsResponse.errorCode}`); | ||
} | ||
} | ||
})); | ||
console.log(tradeArrayToReturn); | ||
return json(tradeArrayToReturn, { status: 200 }); | ||
}) satisfies RequestHandler |
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,61 @@ | ||
import { json, redirect, type RequestHandler } from '@sveltejs/kit'; | ||
import type { CapitalComUserAccounts, SwitchAccountsResponse } from "$lib/types"; | ||
import { UserCST, UserXSecurityToken } from "$lib/stores"; | ||
|
||
let userCST: string; | ||
UserCST.subscribe((value: string) => { | ||
userCST = value; | ||
}); | ||
|
||
let userXSecurityToken: string; | ||
UserXSecurityToken.subscribe((value: string) => { | ||
userXSecurityToken = value; | ||
}); | ||
|
||
|
||
export const POST: RequestHandler = (async ({ cookies, request }) => { | ||
const capitalComCST = cookies.get("CAPITALCOM-CST"); | ||
const capitalComSecurityToken = cookies.get("CAPITALCOM-X-SECURITY-TOKEN"); | ||
if(userCST !== capitalComCST || userXSecurityToken !== capitalComSecurityToken) { throw redirect(302, "/login") } | ||
|
||
const userAccountsResponse: Response = await fetch("https://api-capital.backend-capital.com/api/v1/accounts", { | ||
method: "GET", | ||
headers: { | ||
"X-SECURITY-TOKEN": userXSecurityToken, | ||
"CST": userCST, | ||
"Content-Type" : "application/json" | ||
}, | ||
redirect: "follow" | ||
}); | ||
|
||
let parsedUserAccountsResponse: CapitalComUserAccounts = await userAccountsResponse.json(); | ||
if(parsedUserAccountsResponse.errorCode !== undefined) { console.log(`Error while getting all acounts for user: ${parsedUserAccountsResponse.errorCode}`); return json({ error: `Error while getting all acounts for user: ${parsedUserAccountsResponse.errorCode}` }, { status: 500 }); } | ||
if(parsedUserAccountsResponse.accounts?.length === 0) { console.log(`User has no accounts!: ${parsedUserAccountsResponse}`); return json({ error: "The selected account does not have any trading accounts." }, { status: 500 }); } | ||
|
||
let submittedAccountName = JSON.parse((await request.text())).selectedAccount; | ||
if(parsedUserAccountsResponse.accounts!.find(account => account.accountName === submittedAccountName) !== undefined) { | ||
const parsedSwitchAccountResponse: SwitchAccountsResponse = await (await fetch("https://api-capital.backend-capital.com/api/v1/session", { | ||
method: "PUT", | ||
headers: { | ||
"X-SECURITY-TOKEN": userXSecurityToken, | ||
"CST": userCST, | ||
"Content-Type" : "application/json" | ||
}, | ||
body: JSON.stringify({ | ||
accountId: parsedUserAccountsResponse.accounts!.find(account => account.accountName === submittedAccountName)?.accountId | ||
}), | ||
redirect: "follow" | ||
})).json(); | ||
|
||
if(parsedSwitchAccountResponse.errorCode !== undefined && parsedSwitchAccountResponse.errorCode !== "error.not-different.accountId") { | ||
console.log(`Error while selecting account: ${parsedSwitchAccountResponse.errorCode!}`); return json({ error: `Error while switching account: ${parsedSwitchAccountResponse.errorCode!}` }, { status: 500 }); | ||
} else if(parsedSwitchAccountResponse.errorCode === "error.not-different.accountId") { | ||
return json({ success: true, msg: `Already signed in to ${submittedAccountName}.` }, { status: 200 }); | ||
} | ||
|
||
return json({ success: true }, { status: 200 }); | ||
} else { | ||
return json({ error: `The selected trading account "${submittedAccountName}" does not exist.`.replace("\"", "") }, { status: 500 }); | ||
} | ||
|
||
}); |
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 @@ | ||
export const ssr = false |
Oops, something went wrong.