import React from 'react'; import PropTypes from 'prop-types'; import Grid from '@material-ui/core/Grid'; import Button from '@material-ui/core/Button'; import Typography from '@material-ui/core/Typography'; import {makeStyles} from '@material-ui/core/styles'; import {attachStrategyOn, querySessions, querySessionSymbols} from "../api/bbgo"; import TextField from '@material-ui/core/TextField'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormHelperText from '@material-ui/core/FormHelperText'; import InputLabel from '@material-ui/core/InputLabel'; import FormControl from '@material-ui/core/FormControl'; import Radio from '@material-ui/core/Radio'; import RadioGroup from '@material-ui/core/RadioGroup'; import FormLabel from '@material-ui/core/FormLabel'; import Select from '@material-ui/core/Select'; import MenuItem from '@material-ui/core/MenuItem'; import Alert from '@material-ui/lab/Alert'; import Box from "@material-ui/core/Box"; import NumberFormat from 'react-number-format'; function parseFloatValid(s) { if (s) { const f = parseFloat(s) if (!isNaN(f)) { return f } } return null } function parseFloatCall(s, cb) { if (s) { const f = parseFloat(s) if (!isNaN(f)) { cb(f) } } } function StandardNumberFormat(props) { const {inputRef, onChange, ...other} = props; return ( { onChange({ target: { name: props.name, value: values.value, }, }); }} thousandSeparator isNumericString /> ); } StandardNumberFormat.propTypes = { inputRef: PropTypes.func.isRequired, name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, }; function PriceNumberFormat(props) { const {inputRef, onChange, ...other} = props; return ( { onChange({ target: { name: props.name, value: values.value, }, }); }} thousandSeparator isNumericString prefix="$" /> ); } PriceNumberFormat.propTypes = { inputRef: PropTypes.func.isRequired, name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, }; const useStyles = makeStyles((theme) => ({ formControl: { marginTop: theme.spacing(1), marginBottom: theme.spacing(1), minWidth: 120, }, buttons: { display: 'flex', justifyContent: 'flex-end', marginTop: theme.spacing(2), paddingTop: theme.spacing(2), paddingBottom: theme.spacing(2), '& > *': { marginLeft: theme.spacing(1), } }, })); export default function ConfigureGridStrategyForm({onBack, onAdded}) { const classes = useStyles(); const [errors, setErrors] = React.useState({}) const [sessions, setSessions] = React.useState([]); const [activeSessionSymbols, setActiveSessionSymbols] = React.useState([]); const [selectedSessionName, setSelectedSessionName] = React.useState(null); const [selectedSymbol, setSelectedSymbol] = React.useState(''); const [quantityBy, setQuantityBy] = React.useState('fixedAmount'); const [upperPrice, setUpperPrice] = React.useState(30000.0); const [lowerPrice, setLowerPrice] = React.useState(10000.0); const [fixedAmount, setFixedAmount] = React.useState(100.0); const [fixedQuantity, setFixedQuantity] = React.useState(1.234); const [gridNumber, setGridNumber] = React.useState(20); const [profitSpread, setProfitSpread] = React.useState(100.0); const [response, setResponse] = React.useState({}); React.useEffect(() => { querySessions((sessions) => { setSessions(sessions) }); }, []) const handleAdd = (event) => { const payload = { symbol: selectedSymbol, gridNumber: parseFloatValid(gridNumber), profitSpread: parseFloatValid(profitSpread), upperPrice: parseFloatValid(upperPrice), lowerPrice: parseFloatValid(lowerPrice), } switch (quantityBy) { case "fixedQuantity": payload.quantity = parseFloatValid(fixedQuantity); break; case "fixedAmount": payload.amount = parseFloatValid(fixedAmount); break; } if (!selectedSessionName) { setErrors({ session: true }) return } if (!selectedSymbol) { setErrors({ symbol: true }) return } console.log(payload) attachStrategyOn(selectedSessionName, "grid", payload, (response) => { console.log(response) setResponse(response) if (onAdded) { setTimeout(onAdded, 3000) } }).catch((err) => { console.error(err); setResponse(err.response.data) }).finally(() => { setErrors({}) }) }; const handleQuantityBy = (event) => { setQuantityBy(event.target.value); }; const handleSessionChange = (event) => { const sessionName = event.target.value; setSelectedSessionName(sessionName) querySessionSymbols(sessionName, (symbols) => { setActiveSessionSymbols(symbols); }).catch((err) => { console.error(err); setResponse(err.response.data) }) }; const sessionMenuItems = sessions.map((session, index) => { return ( {session.name} ); }) const symbolMenuItems = activeSessionSymbols.map((symbol, index) => { return ( {symbol} ); }) return ( Add Grid Strategy Fixed price band grid strategy uses the fixed price band to place buy/sell orders. This strategy places sell orders above the current price, places buy orders below the current price. If any of the order is executed, then it will automatically place a new profit order on the reverse side. Session Select the exchange session you want to mount this strategy. Market Select the market you want to run this strategy { parseFloatCall(event.target.value, setUpperPrice) }} value={upperPrice} InputProps={{ inputComponent: PriceNumberFormat, }} /> { parseFloatCall(event.target.value, setLowerPrice) }} value={lowerPrice} InputProps={{ inputComponent: PriceNumberFormat, }} /> { parseFloatCall(event.target.value, setProfitSpread) }} value={profitSpread} InputProps={{ inputComponent: StandardNumberFormat, }} /> Order Quantity By } label="Fixed Amount"/> } label="Fixed Quantity"/> {quantityBy === "fixedQuantity" ? ( { parseFloatCall(event.target.value, setFixedQuantity) }} value={fixedQuantity} InputProps={{ inputComponent: StandardNumberFormat, }} /> ) : null} {quantityBy === "fixedAmount" ? ( { parseFloatCall(event.target.value, setFixedAmount) }} value={fixedAmount} InputProps={{ inputComponent: PriceNumberFormat, }} /> ) : null} { parseFloatCall(event.target.value, setGridNumber) }} value={gridNumber} InputProps={{ inputComponent: StandardNumberFormat, }} />
{ response ? response.error ? ( {response.error} ) : response.success ? ( Strategy Added ) : null : null }
); }