Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ft: [strat] buying option strategy #19

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "node",
"request": "attach",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"skipFiles": ["${workspaceFolder}/node_modules/**/*.js", "<node_internals>/**"],
"port": 9229
}
]
Expand Down
12 changes: 12 additions & 0 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Adam Grimes

- A range that breaks out in the continuation of the trend, is not as exciting
as a range that breaks out opposite to the trend - as that leads to a more sharper fallout

- Ranges can expand without breaking

- Consolidation against the range sets up failure
- Bouncing ball pattern near S/R levels,
- Multiple tests weaken the range.

- Most ranges are continuation ranges - we expect trends to continue
27 changes: 17 additions & 10 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
Status 4.45am
- [NOW] Disable auto selected NF and BNF in DOS form
- UI - throw an error if nothing is selected
- [NOW] make instruments file available in redis on first call
- [NOW] add an option to not take the trade if skew is greater than another custom user entered skew %. So ideal skew can be 10%, but reject skew can be 30%.
- [LATER] Reduce delay for everyone else. Save response in redis cache from signlax repo
- [LATER] calculate skews of ATM+-<step> strikes and take trade in whatever has least skew

- have wrapped up all major pieces for the BNF directional option selling
/**
https://www.investopedia.com/terms/s/syntheticfuturescontract.asp

A synthetic futures contract uses put and call options with the same strike price and expiration date to simulate a traditional futures contract.
so, basically what I am suggesting is … for your ATM straddle follow this algo
Look at spot. Pick strike closest to it … say S1
Get prices of S1 CE and S1 PE (these will be very liquid)
compute F = S1 + CE - PE
Compute S2 closest to F
Use S2 as the apex of your straddle. If S2 is different from S2, get prices of CE and PE again
Then follow usual procedure

## TODOs
1. ✅ Test if the exit strat works - haven't been able to check if we're able to get ST value of option that's sold
2. ✅ Code the logic that'd place another order as per martingale
3. ✅ deploy signalx.trade on DO
4. ✅ build the khaching connection to signalx.trade
6. ✅ Enable form fields for customization
5. ✅ DO NOT take another trade if it's beyond 2pm
7. ✅ don't send modify order if difference is small ie 3-5% option price.
**/
2 changes: 2 additions & 0 deletions components/trades/OptionBuyingStrategyTradeSetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import OBSTradeSetup from './optionBuyingStrategy';
export default OBSTradeSetup;
108 changes: 108 additions & 0 deletions components/trades/optionBuyingStrategy/TradeSetupDetails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Button, Grid, Paper } from '@material-ui/core';
import dayjs from 'dayjs';
import React from 'react';
import TimeAgo from 'react-timeago';
import useSWR from 'swr';

import { INSTRUMENT_DETAILS, STRATEGIES_DETAILS } from '../../../lib/constants';
import OrdersTable from '../../lib/ordersTable';
// import OrdersTable from '../lib/ordersTable';

const Details = ({ job, strategy, onDeleteJob }) => {
const { data: jobDetails, error } = useSWR(`/api/get_job?id=${job.id}`);

if (error) {
onDeleteJob({ jobId: job.id });
return null;
}

function handleDeleteJob({ jobId }) {
const currentState = jobDetails?.current_state;
if (currentState === 'delayed' || currentState === 'waiting') {
const userResponse = window.confirm('This will delete the scheduled task. Are you sure?');
if (userResponse) {
onDeleteJob({ jobId });
}
} else {
onDeleteJob({ jobId });
}
}

const strategyDetails = STRATEGIES_DETAILS[strategy];
const { runAt, runNow, lots, instrument } = job.data;

const humanTime = dayjs(runAt).format('h.mma');
const Heading = () => (
<>
#{job.id} · {strategyDetails.heading}{' '}
{runNow ? (
<>
was run <TimeAgo date={new Date(job.timestamp)} />.
</>
) : (
<>is scheduled to run at {humanTime}.</>
)}
</>
);

const deleteDisclaimer = !runNow
? `⏰ This task can be safely deleted before the clock hits ${humanTime}.`
: null;

return (
<Paper style={{ padding: 16, marginBottom: 32 }}>
<h4>
<Heading />
</h4>

<h2>{INSTRUMENT_DETAILS[instrument].displayName}</h2>

<OrdersTable
headerItems={[
{ title: 'Lots', align: 'left' },
{ title: 'Scheduled time', align: 'left' }
]}
rows={[
[
{ value: lots, align: 'left' },
{ value: humanTime, align: 'left' }
]
]}
/>

<div>
<h3>Status: {jobDetails?.current_state?.toUpperCase() || 'Loading...'}</h3>
</div>

<Grid item style={{ marginTop: 16 }}>
{/* <div style={{ marginBottom: 16 }}>
{jobDetails?.current_state === 'completed' ? (
<OrdersTable
rows={jobDetails.job.returnvalue.rawKiteOrdersResponse.map((row) => {
const [item] = row;
return {
product: item.product,
instrument: item.tradingsymbol,
qty: item.quantity * (item.transaction_type === 'SELL' ? -1 : 1),
avg: item.average_price
};
})}
/>
) : null}
</div> */}
<Button
variant="contained"
type="button"
onClick={() => handleDeleteJob({ jobId: job.id })}
disabled={jobDetails?.current_state === 'active'}>
Cleanup Job
</Button>
{['delayed', 'waiting'].includes(jobDetails?.current_state) && deleteDisclaimer ? (
<p>{deleteDisclaimer}</p>
) : null}
</Grid>
</Paper>
);
};

export default Details;
111 changes: 111 additions & 0 deletions components/trades/optionBuyingStrategy/TradeSetupForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
Button,
Checkbox,
CssBaseline,
Divider,
FormControl,
FormControlLabel,
FormGroup,
FormLabel,
Grid,
Link,
MenuItem,
Paper,
Radio,
RadioGroup,
Select,
TextField,
Typography
} from '@material-ui/core';
import Box from '@material-ui/core/Box';
import useSWR from 'swr';

import { INSTRUMENT_DETAILS } from '../../../lib/constants';

const TradeSetupForm = ({ enabledInstruments, state, onChange, onSubmit }) => {
const { error: fyersProfileError } = useSWR(`/api/fyers_profile`);

return (
<form noValidate>
<Paper style={{ padding: 16 }}>
{fyersProfileError ? (
<>
<div style={{ marginBottom: '16px' }}>
<Typography variant="h6" component="span">
<Link href="/api/broker_auth/fyers">&lt;Login with Fyers to trade this&gt;</Link>
</Typography>
</div>
<Divider />
</>
) : null}
<h3>Setup new trade</h3>
<Grid container alignItems="flex-start" spacing={2}>
<Grid item xs={12}>
<FormControl component="fieldset">
<FormLabel component="legend">Instruments</FormLabel>
<FormGroup row>
{enabledInstruments.map((instrument) => (
<FormControlLabel
key={instrument}
label={INSTRUMENT_DETAILS[instrument].displayName}
control={
<Checkbox
name="instruments"
checked={state.instruments[instrument]}
onChange={() => {
onChange({
instruments: {
[instrument]: !state.instruments[instrument]
}
});
}}
/>
}
/>
))}
</FormGroup>
</FormControl>
</Grid>
<Grid item xs={12}>
<TextField
fullWidth
name="lots"
value={state.lots}
onChange={(e) => onChange({ lots: e.target.value || '' })}
label="Lots"
/>
</Grid>

<Grid item xs={12}>
<Button
disabled={fyersProfileError}
variant="contained"
color="primary"
type="button"
onClick={() => onSubmit()}>
Let&apos;s go!
</Button>
</Grid>
<Grid item xs={12}>
<Typography>
<Box fontStyle="italic" fontSize={14}>
<p>Note —</p>
<ol>
<li>This strategy takes trades between 9.30-11am and 1-3pm.</li>
<li>
Depending on when you set this up, the tasks can be deleted if they haven&apos;t
been triggered yet.
</li>
<li>
The backtests of this strategy can be <Link>found here</Link>.
</li>
</ol>
</Box>
</Typography>
</Grid>
</Grid>
</Paper>
</form>
);
};
export default TradeSetupForm;
Loading