Skip to content

Commit

Permalink
Merge pull request #876 from CAFECA-IO/fix/quote
Browse files Browse the repository at this point in the history
play: 🐸 show correct quotation after ticker changed #847
  • Loading branch information
Luphia authored Jun 13, 2023
2 parents 8c3987e + 25c15d1 commit 4934dbf
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 69 deletions.
74 changes: 71 additions & 3 deletions src/components/open_position_item/open_position_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import {POSITION_CLOSE_COUNTDOWN_SECONDS, FRACTION_DIGITS} from '../../constants
import {MarketContext} from '../../contexts/market_context';
import {IDisplayCFDOrder} from '../../interfaces/tidebit_defi_background/display_accepted_cfd_order';
import {useTranslation} from 'react-i18next';
import {defaultResultFailed} from '../../interfaces/tidebit_defi_background/result';
import {IQuotation} from '../../interfaces/tidebit_defi_background/quotation';
import {ToastTypeAndText} from '../../constants/toast_type';
import {ToastId} from '../../constants/toast_id';
import {Code} from '../../constants/code';

type TranslateFunction = (s: string) => string;
interface IOpenPositionItemProps {
Expand All @@ -33,6 +38,7 @@ const OpenPositionItem = ({openCfdDetails}: IOpenPositionItemProps) => {
dataUpdateFormModalHandler,
visiblePositionClosedModalHandler,
dataPositionClosedModalHandler,
toast,
} = useGlobal();

const openItemClickHandler = () => {
Expand Down Expand Up @@ -67,6 +73,7 @@ const OpenPositionItem = ({openCfdDetails}: IOpenPositionItemProps) => {
openCfdDetails.targetAsset,
openCfdDetails.typeOfPosition
);

const pnl = toPnl({
openPrice,
closePrice,
Expand Down Expand Up @@ -94,9 +101,70 @@ const OpenPositionItem = ({openCfdDetails}: IOpenPositionItemProps) => {

const denominator = remainSecs < 60 ? 60 : remainSecs < 3600 ? 60 : 24;

const squareClickHandler = () => {
dataPositionClosedModalHandler(openCfdDetails);
visiblePositionClosedModalHandler();
const squareClickHandler = async () => {
await getQuotation();
};

const toDisplayCloseOrder = (cfd: IDisplayCFDOrder, quotation: IQuotation): IDisplayCFDOrder => {
const pnlSoFar = toPnl({
openPrice: cfd.openPrice,
closePrice: quotation.price,
amount: cfd.amount,
typeOfPosition: cfd.typeOfPosition,
spread: marketCtx.getTickerSpread(cfd.targetAsset),
});

return {
...cfd,
closePrice: quotation.price,
pnl: pnlSoFar,
};
};

const getQuotation = async () => {
let quotation = {...defaultResultFailed};
const oppositeTypeOfPosition =
openCfdDetails?.typeOfPosition === TypeOfPosition.BUY
? TypeOfPosition.SELL
: TypeOfPosition.BUY;

try {
quotation = await marketCtx.getCFDQuotation(openCfdDetails?.ticker, oppositeTypeOfPosition);

const data = quotation.data as IQuotation;
if (
quotation.success &&
data.typeOfPosition === oppositeTypeOfPosition &&
data.ticker.split('-')[0] === openCfdDetails.ticker &&
quotation.data !== null
) {
const displayedCloseOrder = toDisplayCloseOrder(openCfdDetails, data);
dataPositionClosedModalHandler(displayedCloseOrder);

visiblePositionClosedModalHandler();
} else {
toast({
type: ToastTypeAndText.ERROR.type,
toastId: ToastId.GET_QUOTATION_ERROR,
message: `${t('POSITION_MODAL.ERROR_MESSAGE')} (${
Code.CANNOT_GET_QUOTATION_FROM_CONTEXT
})`,
typeText: t(ToastTypeAndText.ERROR.text),
isLoading: false,
autoClose: false,
});
}
} catch (err) {
// TODO: Report error to backend (20230613 - Shirley)
toast({
type: ToastTypeAndText.ERROR.type,
toastId: ToastId.GET_QUOTATION_ERROR,
message: `${t('POSITION_MODAL.ERROR_MESSAGE')} (${Code.UNKNOWN_ERROR_IN_COMPONENT})`,
typeText: t(ToastTypeAndText.ERROR.text),
isLoading: false,
autoClose: false,
});
}
};

/* Info: (20230411 - Julian) 折線圖參考線的優先顯示順序:
Expand Down
36 changes: 2 additions & 34 deletions src/components/open_sub_tab/open_sub_tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ const OpenSubTab = () => {
const userCtx = useContext(UserContext);
const marketCtx = useContext(MarketContext);

// const initState = {
// longPrice: 0,
// shortPrice: 0,
// };
//const [caledPrice, setCaledPrice, caledPriceRef] = useStateRef(initState);
const [isLoading, setIsLoading] = useState(true);
const [cfds, setCfds] = useState<IDisplayCFDOrder[]>([]);
Expand All @@ -37,30 +33,6 @@ const OpenSubTab = () => {
};
*/

// Deprecated (20230610 - Julian)
// useEffect(() => {
// const buyPrice = !!marketCtx.selectedTicker?.price
// ? roundToDecimalPlaces(
// marketCtx.selectedTicker.price *
// (1 + (marketCtx.tickerLiveStatistics?.spread ?? DEFAULT_SPREAD)),
// 2
// )
// : 0;

// const sellPrice = !!marketCtx.selectedTicker?.price
// ? roundToDecimalPlaces(
// marketCtx.selectedTicker.price *
// (1 - (marketCtx.tickerLiveStatistics?.spread ?? DEFAULT_SPREAD)),
// 2
// )
// : 0;

// setCaledPrice({
// longPrice: buyPrice,
// shortPrice: sellPrice,
// });
// }, [marketCtx.selectedTicker?.price]);

useEffect(() => {
const cfdList = userCtx.openCFDs
.map(cfd => {
Expand All @@ -71,12 +43,6 @@ const OpenSubTab = () => {
const spread = marketCtx.getTickerSpread(cfd.targetAsset);
*/
const tickerPrice = marketCtx.availableTickers[cfd.targetAsset]?.price;
/**
* Info: (20230428 - Shirley)
* without `positionLineGraph`, use market price to calculate
* without `market price`, use the open price of the CFD to get PNL === 0 and display `--`
* (OpenPositionItem & UpdateFormModal)
*/

/** Deprecated: (20230608 - tzuhan)
const currentPrice =
Expand Down Expand Up @@ -105,9 +71,11 @@ const OpenSubTab = () => {

setCfds(cfdList);
}, [userCtx.openCFDs]);

useEffect(() => {
setTimeout(() => setIsLoading(false), SKELETON_DISPLAY_TIME);
}, [userCtx.openCFDs]);

const openPositionList =
isLoading || userCtx.isLoadingCFDs ? (
<Skeleton count={10} height={150} />
Expand Down
85 changes: 56 additions & 29 deletions src/components/position_closed_modal/position_closed_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,20 @@ const PositionClosedModal = ({
const globalCtx = useGlobal();
const userCtx = useContext(UserContext);

const predictedClosePrice = marketCtx.predictCFDClosePrice(
openCfdDetails.targetAsset,
openCfdDetails.typeOfPosition
);

const spread = marketCtx.getTickerSpread(openCfdDetails.targetAsset);
const pnl = toPnl({
openPrice: openCfdDetails.openPrice,
closePrice: predictedClosePrice,
amount: openCfdDetails.amount,
typeOfPosition: openCfdDetails.typeOfPosition,
spread: spread,
});
/* Deprecated: changing pnl when fixed closed price
// const predictedClosePrice = marketCtx.predictCFDClosePrice(
// openCfdDetails.targetAsset,
// openCfdDetails.typeOfPosition
// );
// const spread = marketCtx.getTickerSpread(openCfdDetails.targetAsset);
// const pnl = toPnl({
// openPrice: openCfdDetails.openPrice,
// closePrice: predictedClosePrice,
// amount: openCfdDetails.amount,
// typeOfPosition: openCfdDetails.typeOfPosition,
// spread: spread,
// });
*/

const [quotationError, setQuotationError, quotationErrorRef] = useStateRef(false);
const [quotationErrorMessage, setQuotationErrorMessage, quotationErrorMessageRef] =
Expand Down Expand Up @@ -121,7 +122,11 @@ const PositionClosedModal = ({
const displayedGuaranteedStopSetting = !!openCfdDetails?.guaranteedStop ? 'Yes' : 'No';

const displayedPnLSymbol =
pnl?.type === ProfitState.PROFIT ? '+' : pnl?.type === ProfitState.LOSS ? '-' : '';
openCfdDetails?.pnl?.type === ProfitState.PROFIT
? '+'
: openCfdDetails?.pnl?.type === ProfitState.LOSS
? '-'
: '';

const displayedTypeOfPosition =
openCfdDetails?.typeOfPosition === TypeOfPosition.BUY
Expand All @@ -134,16 +139,16 @@ const PositionClosedModal = ({
: t('POSITION_MODAL.TYPE_SELL');

const displayedPnLColor =
pnl.type === ProfitState.PROFIT
openCfdDetails?.pnl?.type === ProfitState.PROFIT
? TypeOfPnLColor.PROFIT
: pnl.type === ProfitState.LOSS
: openCfdDetails?.pnl?.type === ProfitState.LOSS
? TypeOfPnLColor.LOSS
: TypeOfPnLColor.EQUAL;

const displayedBorderColor =
pnl.type === ProfitState.PROFIT
openCfdDetails?.pnl?.type === ProfitState.PROFIT
? TypeOfBorderColor.PROFIT
: pnl.type === ProfitState.LOSS
: openCfdDetails?.pnl?.type === ProfitState.LOSS
? TypeOfBorderColor.LOSS
: TypeOfBorderColor.EQUAL;

Expand All @@ -163,6 +168,7 @@ const PositionClosedModal = ({
});
return {
...cfd,
closePrice: 0,
pnl: pnlSoFar,
};
};
Expand Down Expand Up @@ -273,7 +279,7 @@ const PositionClosedModal = ({
globalCtx.toast({
type: ToastTypeAndText.ERROR.type,
toastId: ToastId.INCONSISTENT_TICKER_OF_QUOTATION,
message: `[dev] ${quotationErrorMessageRef.current.reason} (${quotationErrorMessageRef.current.code})`,
message: `[t] ${quotationErrorMessageRef.current.reason} (${quotationErrorMessageRef.current.code})`,
typeText: t(ToastTypeAndText.ERROR.text),
isLoading: false,
autoClose: false,
Expand All @@ -287,6 +293,15 @@ const PositionClosedModal = ({
setQuotationError(true);
/* Info: (20230508 - Julian) get quotation error message */
setQuotationErrorMessage({success: false, code: quotation.code, reason: quotation.reason});
// Deprecated: for debug (20230609 - Shirley)
globalCtx.toast({
type: ToastTypeAndText.ERROR.type,
toastId: ToastId.UNKNOWN_ERROR_IN_COMPONENT,
message: `[t] ${quotationErrorMessageRef.current.reason} (${quotationErrorMessageRef.current.code})`,
typeText: t(ToastTypeAndText.ERROR.text),
isLoading: false,
autoClose: false,
});
}
};

Expand Down Expand Up @@ -438,11 +453,15 @@ const PositionClosedModal = ({
autoClose: false,
});
return;
}
const displayedCloseOrder = toDisplayCloseOrder(openCfdDetails, quotation);
globalCtx.dataPositionClosedModalHandler(displayedCloseOrder);
// TODO: check users' signature in userCtx (20230613 - Shirley)
} else if (quotation.ticker.split('-')[0] === openCfdDetails.ticker) {
const displayedCloseOrder = toDisplayCloseOrder(openCfdDetails, quotation);
globalCtx.dataPositionClosedModalHandler(displayedCloseOrder);

setGQuotation(quotation);
setGQuotation(quotation);
setDataRenewedStyle('text-lightWhite');
setQuotationError(false);
}
})();
}, [globalCtx.visiblePositionClosedModal]);

Expand All @@ -451,7 +470,7 @@ const PositionClosedModal = ({
if (!globalCtx.visiblePositionClosedModal) {
setSecondsLeft(DISPLAY_QUOTATION_RENEWAL_INTERVAL_SECONDS);
setDataRenewedStyle('text-lightWhite');

setQuotationError(true);
return;
}

Expand Down Expand Up @@ -535,10 +554,15 @@ const PositionClosedModal = ({
<div className={`${layoutInsideBorder}`}>
<div className="text-lightGray">{t('POSITION_MODAL.CLOSED_PRICE')}</div>
<div className={`${dataRenewedStyle}`}>
{gQuotationRef.current.price?.toLocaleString(
UNIVERSAL_NUMBER_FORMAT_LOCALE,
FRACTION_DIGITS
) ?? 0}{' '}
{openCfdDetails.closePrice
? openCfdDetails.closePrice.toLocaleString(
UNIVERSAL_NUMBER_FORMAT_LOCALE,
FRACTION_DIGITS
)
: gQuotationRef.current.price?.toLocaleString(
UNIVERSAL_NUMBER_FORMAT_LOCALE,
FRACTION_DIGITS
) ?? 0}{' '}
<span className="ml-1 text-lightGray">{unitAsset}</span>
</div>
</div>
Expand All @@ -547,7 +571,10 @@ const PositionClosedModal = ({
<div className="text-lightGray">{t('POSITION_MODAL.PNL')}</div>
<div className={`${pnlRenewedStyle} ${displayedPnLColor}`}>
{displayedPnLSymbol} ${' '}
{pnl?.value.toLocaleString(UNIVERSAL_NUMBER_FORMAT_LOCALE, FRACTION_DIGITS)}
{openCfdDetails?.pnl?.value.toLocaleString(
UNIVERSAL_NUMBER_FORMAT_LOCALE,
FRACTION_DIGITS
)}
</div>
</div>

Expand Down
2 changes: 2 additions & 0 deletions src/constants/toast_id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type IToastId = {
GET_QUOTATION_ERROR: string;
INVALID_CFD_OPEN_REQUEST: string;
INCONSISTENT_TICKER_OF_QUOTATION: string;
UNKNOWN_ERROR_IN_COMPONENT: string;
};

export const ToastId: IToastId = {
Expand All @@ -12,4 +13,5 @@ export const ToastId: IToastId = {
GET_QUOTATION_ERROR: 'GetQuotationError',
INVALID_CFD_OPEN_REQUEST: 'InvalidCFDOpenRequest',
INCONSISTENT_TICKER_OF_QUOTATION: 'InconsistentTickerOfQuotation',
UNKNOWN_ERROR_IN_COMPONENT: 'UnknownErrorInComponent',
};
6 changes: 3 additions & 3 deletions src/contexts/global_context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,8 @@ export const GlobalProvider = ({children}: IGlobalProvider) => {

const [visiblePositionClosedModal, setVisiblePositionClosedModal, visiblePositionClosedModalRef] =
useStateRef<boolean>(false);
const [dataPositionClosedModal, setDataPositionClosedModal] =
useState<IDisplayCFDOrder>(dummyOpenCFD);
const [dataPositionClosedModal, setDataPositionClosedModal, dataPositionClosedModalRef] =
useStateRef<IDisplayCFDOrder>(dummyOpenCFD);

const [visiblePositionOpenModal, setVisiblePositionOpenModal] = useState(false);
const [dataPositionOpenModal, setDataPositionOpenModal] = useState<IDataPositionOpenModal>(
Expand Down Expand Up @@ -1163,7 +1163,7 @@ export const GlobalProvider = ({children}: IGlobalProvider) => {
visiblePositionClosedModal,
visiblePositionClosedModalRef,
visiblePositionClosedModalHandler,
dataPositionClosedModal,
dataPositionClosedModal: dataPositionClosedModalRef.current,
dataPositionClosedModalHandler,

visiblePositionOpenModal,
Expand Down

0 comments on commit 4934dbf

Please sign in to comment.