bonomat
3 years ago
3 changed files with 0 additions and 265 deletions
@ -1,17 +0,0 @@ |
|||
import { ChakraProvider } from "@chakra-ui/react"; |
|||
import React from "react"; |
|||
import ReactDOM from "react-dom"; |
|||
import Taker from "./TakerApp"; |
|||
import theme from "./theme"; |
|||
|
|||
it("renders without crashing", () => { |
|||
const div = document.createElement("div"); |
|||
ReactDOM.render( |
|||
<React.StrictMode> |
|||
<ChakraProvider theme={theme}> |
|||
<Taker /> |
|||
</ChakraProvider> |
|||
</React.StrictMode>, |
|||
div, |
|||
); |
|||
}); |
@ -1,227 +0,0 @@ |
|||
import { |
|||
Box, |
|||
Button, |
|||
Container, |
|||
Divider, |
|||
Grid, |
|||
GridItem, |
|||
HStack, |
|||
Tab, |
|||
TabList, |
|||
TabPanel, |
|||
TabPanels, |
|||
Tabs, |
|||
Text, |
|||
useToast, |
|||
VStack, |
|||
} from "@chakra-ui/react"; |
|||
import React, { useEffect, useState } from "react"; |
|||
import { useAsync } from "react-async"; |
|||
import { useEventSource } from "react-sse-hooks"; |
|||
import { useBackendMonitor } from "./components/BackendMonitor"; |
|||
import { CfdTable } from "./components/cfdtables/CfdTable"; |
|||
import CurrencyInputField from "./components/CurrencyInputField"; |
|||
import createErrorToast from "./components/ErrorToast"; |
|||
import useLatestEvent from "./components/Hooks"; |
|||
import { HttpError } from "./components/HttpError"; |
|||
import { Cfd, intoCfd, intoOrder, Order, StateGroupKey, WalletInfo } from "./components/Types"; |
|||
import Wallet from "./components/Wallet"; |
|||
|
|||
interface CfdOrderRequestPayload { |
|||
order_id: string; |
|||
quantity: number; |
|||
} |
|||
|
|||
interface MarginRequestPayload { |
|||
price: number; |
|||
quantity: number; |
|||
leverage: number; |
|||
} |
|||
|
|||
interface MarginResponse { |
|||
margin: number; |
|||
} |
|||
|
|||
async function postCfdOrderRequest(payload: CfdOrderRequestPayload) { |
|||
let res = await fetch(`/api/cfd/order`, { method: "POST", body: JSON.stringify(payload) }); |
|||
|
|||
if (!res.status.toString().startsWith("2")) { |
|||
const resp = await res.json(); |
|||
throw new HttpError(resp); |
|||
} |
|||
} |
|||
|
|||
async function getMargin(payload: MarginRequestPayload): Promise<MarginResponse> { |
|||
let res = await fetch(`/api/calculate/margin`, { method: "POST", body: JSON.stringify(payload) }); |
|||
|
|||
if (!res.status.toString().startsWith("2")) { |
|||
const resp = await res.json(); |
|||
throw new HttpError(resp); |
|||
} |
|||
|
|||
return res.json(); |
|||
} |
|||
|
|||
export default function App() { |
|||
const toast = useToast(); |
|||
useBackendMonitor(toast, 5000); // 5s timeout
|
|||
|
|||
document.title = "Hermes Taker"; |
|||
|
|||
let source = useEventSource({ source: "/api/feed" }); |
|||
|
|||
const cfdsOrUndefined = useLatestEvent<Cfd[]>(source, "cfds", intoCfd); |
|||
let cfds = cfdsOrUndefined ? cfdsOrUndefined! : []; |
|||
const order = useLatestEvent<Order>(source, "order", intoOrder); |
|||
const walletInfo = useLatestEvent<WalletInfo>(source, "wallet"); |
|||
|
|||
let [quantity, setQuantity] = useState("0"); |
|||
let [margin, setMargin] = useState("0"); |
|||
let [userHasEdited, setUserHasEdited] = useState(false); |
|||
|
|||
let effectiveQuantity = userHasEdited ? quantity : (order?.min_quantity.toString() || "0"); |
|||
|
|||
let { run: calculateMargin } = useAsync({ |
|||
deferFn: async ([payload]: any[]) => { |
|||
try { |
|||
let res = await getMargin(payload as MarginRequestPayload); |
|||
setMargin(res.margin.toString()); |
|||
} catch (e) { |
|||
createErrorToast(toast, e); |
|||
} |
|||
}, |
|||
}); |
|||
|
|||
useEffect(() => { |
|||
if (!order) { |
|||
return; |
|||
} |
|||
let quantity = effectiveQuantity ? Number.parseFloat(effectiveQuantity) : 0; |
|||
let payload: MarginRequestPayload = { |
|||
leverage: order.leverage, |
|||
price: order.price, |
|||
quantity, |
|||
}; |
|||
calculateMargin(payload); |
|||
}, // Eslint demands us to include `calculateMargin` in the list of dependencies.
|
|||
// We don't want that as we will end up in an endless loop. It is safe to ignore `calculateMargin` because
|
|||
// nothing in `calculateMargin` depends on outside values, i.e. is guaranteed to be stable.
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|||
[margin, effectiveQuantity, order]); |
|||
|
|||
const format = (val: any) => `$` + val; |
|||
const parse = (val: any) => val.replace(/^\$/, ""); |
|||
|
|||
let { run: makeNewOrderRequest, isLoading: isCreatingNewOrderRequest } = useAsync({ |
|||
deferFn: async ([payload]: any[]) => { |
|||
try { |
|||
await postCfdOrderRequest(payload as CfdOrderRequestPayload); |
|||
} catch (e) { |
|||
createErrorToast(toast, e); |
|||
} |
|||
}, |
|||
}); |
|||
|
|||
const opening = cfds.filter((value) => value.state.getGroup() === StateGroupKey.OPENING); |
|||
const open = cfds.filter((value) => value.state.getGroup() === StateGroupKey.OPEN); |
|||
const closed = cfds.filter((value) => value.state.getGroup() === StateGroupKey.CLOSED); |
|||
|
|||
return ( |
|||
<Container maxWidth="120ch" marginTop="1rem"> |
|||
<HStack spacing={5}> |
|||
<VStack> |
|||
<Wallet walletInfo={walletInfo} /> |
|||
<Grid |
|||
gridTemplateColumns="max-content auto" |
|||
shadow="md" |
|||
padding={5} |
|||
rowGap={5} |
|||
columnGap={5} |
|||
width="100%" |
|||
alignItems="center" |
|||
> |
|||
<Text align={"left"}>Order Price:</Text> |
|||
<Text>{order?.price}</Text> |
|||
|
|||
<Text align={"left"}>Available Quantity:</Text> |
|||
<Text> |
|||
{order ? (format(order?.min_quantity) + "-" + format!(order?.max_quantity)) : "None"} |
|||
</Text> |
|||
<Text>Quantity:</Text> |
|||
<CurrencyInputField |
|||
onChange={(valueString: string) => { |
|||
setUserHasEdited(true); |
|||
setQuantity(parse(valueString)); |
|||
if (!order) { |
|||
return; |
|||
} |
|||
let quantity = valueString ? Number.parseFloat(valueString) : 0; |
|||
let payload: MarginRequestPayload = { |
|||
leverage: order.leverage, |
|||
price: order.price, |
|||
quantity, |
|||
}; |
|||
calculateMargin(payload); |
|||
}} |
|||
value={format(effectiveQuantity)} |
|||
min={order?.min_quantity} |
|||
max={order?.max_quantity} |
|||
/> |
|||
|
|||
<Text>Margin in BTC:</Text> |
|||
<Text>{margin}</Text> |
|||
|
|||
<Text>Leverage:</Text> |
|||
<HStack spacing={5}> |
|||
<Button disabled={true}>x1</Button> |
|||
<Button colorScheme="blue" variant="solid">x{order ? order.leverage : 2}</Button> |
|||
<Button disabled={true}>x5</Button> |
|||
</HStack> |
|||
|
|||
<GridItem colSpan={2}> |
|||
<Divider /> |
|||
</GridItem> |
|||
|
|||
<GridItem colSpan={2} textAlign="center"> |
|||
<Button |
|||
disabled={isCreatingNewOrderRequest || !order} |
|||
variant={"solid"} |
|||
colorScheme={"blue"} |
|||
width="100%" |
|||
onClick={() => { |
|||
let payload: CfdOrderRequestPayload = { |
|||
order_id: order!.id, |
|||
quantity: Number.parseFloat(effectiveQuantity), |
|||
}; |
|||
makeNewOrderRequest(payload); |
|||
}} |
|||
> |
|||
BUY LONG |
|||
</Button> |
|||
</GridItem> |
|||
</Grid> |
|||
</VStack> |
|||
<Box width="100%" /> |
|||
</HStack> |
|||
<Tabs marginTop={5}> |
|||
<TabList> |
|||
<Tab>Open [{open.length}]</Tab> |
|||
<Tab>Opening [{opening.length}]</Tab> |
|||
<Tab>Closed [{closed.length}]</Tab> |
|||
</TabList> |
|||
|
|||
<TabPanels> |
|||
<TabPanel> |
|||
<CfdTable data={open} /> |
|||
</TabPanel> |
|||
<TabPanel> |
|||
<CfdTable data={opening} /> |
|||
</TabPanel> |
|||
<TabPanel> |
|||
<CfdTable data={closed} /> |
|||
</TabPanel> |
|||
</TabPanels> |
|||
</Tabs> |
|||
</Container> |
|||
); |
|||
} |
@ -1,21 +0,0 @@ |
|||
import { ChakraProvider } from "@chakra-ui/react"; |
|||
import React from "react"; |
|||
import ReactDOM from "react-dom"; |
|||
import { BrowserRouter } from "react-router-dom"; |
|||
import { EventSourceProvider } from "react-sse-hooks"; |
|||
import "./index.css"; |
|||
import App from "./TakerApp"; |
|||
import theme from "./theme"; |
|||
|
|||
ReactDOM.render( |
|||
<React.StrictMode> |
|||
<ChakraProvider theme={theme}> |
|||
<EventSourceProvider> |
|||
<BrowserRouter> |
|||
<App /> |
|||
</BrowserRouter> |
|||
</EventSourceProvider> |
|||
</ChakraProvider> |
|||
</React.StrictMode>, |
|||
document.getElementById("root"), |
|||
); |
Loading…
Reference in new issue