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

feat: a call spread option contract and tests. #1854

Merged
merged 5 commits into from
Oct 29, 2020
Merged

Conversation

Chris-Hibbert
Copy link
Contributor

Implementation of a fully collateralized call spread option, following Joe
Clark's description. This is a combination of a bought call option and a sold
call option at a higher strike price. The contracts are sold in pairs, and the
buyers of the two positions together invest the entire amount that will be
paid out.

This option is settled financially. Neither party is expected to have
ownership of the underlying asset at the start, and neither expects to take
delivery at closing.

zoe.startInstance() takes an issuerKeywordRecord that specifies the issuers
for the keywords Underlying, Strike, and Collateral. The payout uses
Collateral. The price oracle quotes the value of the Underlying in the same
units as the Strike prices.

creatorFacet has a method makeInvitationPair(), that takes terms
that specifies { expiration, underlyingAmount, priceAuthority, strikePrice1,
strikePrice2, settlementAmount, buyPercent }.
ownerFacet.makeInvitationPair() returns two invitations, which can be sold
separately. They settle when the priceAuthority announces the settlement amout
as of it's pre-programmed closing time.

closes: #1829

@Chris-Hibbert Chris-Hibbert marked this pull request as draft October 9, 2020 21:13
@Chris-Hibbert Chris-Hibbert self-assigned this Oct 9, 2020
@Chris-Hibbert Chris-Hibbert added the Zoe package: Zoe label Oct 9, 2020
@Chris-Hibbert Chris-Hibbert force-pushed the 1829-callSpread branch 2 times, most recently from 46a3e1d to a99f2c7 Compare October 26, 2020 18:35
Implementation of a fully collateralized call spread option, following Joe
Clark's description. This is a combination of a bought call option and a sold
call option at a higher strike price. The contracts are sold in pairs, and the
buyers of the two positions together invest the entire amount that will be
paid out.

This option is settled financially. Neither party is expected to have
ownership of the underlying asset at the start, and neither expects to take
delivery at closing.

zoe.startInstance() takes an issuerKeywordRecord that specifies the issuers
for the keywords Underlying, Strike, and Collateral. The payout uses
Collateral. The price oracle quotes the value of the Underlying in the same
units as the Strike prices.

creatorFacet has a method makeInvitationPair(), that takes terms
that specifies { expiration, underlyingAmount, priceAuthority, strikePrice1,
strikePrice2, settlementAmount, buyPercent }.
ownerFacet.makeInvitationPair() returns two invitations, which can be sold
separately. They settle when the priceAuthority announces the settlement amout
as of it's pre-programmed closing time.

closes: #1829
@Chris-Hibbert Chris-Hibbert marked this pull request as ready for review October 26, 2020 19:04
Copy link
Contributor

@katelynsills katelynsills left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment that may change the contract pretty significantly. Will come back for more detailed review

packages/zoe/src/contracts/callSpread.js Outdated Show resolved Hide resolved
Copy link
Contributor

@katelynsills katelynsills left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of small nitpicks but overall everything looks good. I would like to see the settlement code that calculates the share given to long and short positions tested in unit tests, if possible.


/**
* This contract implements a fully collateralized call spread. This is a
* combination of a call option bought at one strike price and a second call
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Joe describes this as "a call at a lower strike and a put at a higher strike". I think a sold call option is different than a put.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"One contract to rule them all" says "A more general structure is a call spread, which is a bought call at a lower strike and a sold call at a higher strike. This generalises calls, puts, binaries (including prediction markets), and futures." It later says (under "Fully collateralized call spread") "This is a call at a lower strike and a put at a higher strike."

I think the second is a mistake. It would produce the right outcomes for the long position, but the short position wouldn't have all the rights they should. I've asked for clarification in the doc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Joe responded that they are both calls. The earlier (in the document) statement was correct.

/**
* This contract implements a fully collateralized call spread. This is a
* combination of a call option bought at one strike price and a second call
* option sold at a higher price. The contracts are sold in pairs, and the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* option sold at a higher price. The contracts are sold in pairs, and the
* option sold at a higher price. The invitations are sold in pairs, and the

I don't think we want to call the invitations contracts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this contract is not about selling invitations at all - that's a different level. This contract produces invitations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep. thanks for the correction.

* purchaser have ownership of the underlying asset at the start, and the
* beneficiaries shouldn't expect to take delivery at closing.
*
* The issuerKeywordRecord specifies the issuers for four keywords: Underlying,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Options shouldn't need an issuer specified. It's a Zoe invitation, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, Zoe doesn't know about the invitationIssuer on a per contract level. Huh, wonder if we should pre-register that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could go either way on that. We haven't needed it for other contracts to date. But you're right, it's a general Zoe facility.

Comment on lines 52 to 53
* The creatorInvitation has terms that include the amounts of the two options
* as longOption and shortOption. When the creatorInvitation is exercised, the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we mean terms or customProperties?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right.

Comment on lines +59 to +62
* + create separate invitations to purchase the pieces of the option pair.
* (This would remove the current requirement that an intermediary have the
* total collateral available before the option descriptions have been
* created.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's no purchasing of the option pair happening in this contract. The creator isn't purchasing them, and if we split up that role, the two parties wouldn't be purchasing the options either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is currently no purchasing of the option pair in this contract.

This goes back to my previous approach. I think it would still be valuable, as it's required in order to not have an intermediary have to front the funds.

terms,
);

const optionAmount = await invitationIssuer.getAmountOf(creatorInvitation);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not getInvitationDetails?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good Point.


const aliceProposal = harden({
want: { LongOption: longOptionAmount, ShortOption: shortOptionAmount },
give: { Collateral: bucks(300) },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we call this margin instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a fully collateralized call spread, so there's no margin.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think people call "collateral" margin even when it is fully collateralized, but I could be wrong. Take a look at Joe's doc.

Comment on lines 141 to 142
const aliceOption = await aliceSeat.getOfferResult();
t.truthy(invitationIssuer.isLive(aliceOption));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hang on, there is no offer result returned from the creatorInvitation seat. How is this happening?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, invitationIssuer.isLive returns a promise which is truthy. This is not testing what it should be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep. thanks.

// Underlying is in Simoleans. Collateral, strikePrice and Payout are in bucks.
// Value is in Moola. The price oracle takes an amount in Underlying, and
// gives the value in Moola.
test('callSpread below Strike1', async t => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice to have unit tests of more of the internals of the contract, like the collateralShare calculations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

bucks(225),
);

// Bob buys the Short invitation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Bob buys the Short invitation
// Carol buys the Short invitation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Chris-Hibbert and others added 3 commits October 28, 2020 09:50
This includes changes from the base PR and the separate PR for the
updates to the oracle API.
extract calculation for testing purposes.
save the invitationIssuer as an issuer in the contract
exit contract when done.
use trade() rathern than reallocate()
some renaming
@Chris-Hibbert Chris-Hibbert merged commit db0962b into master Oct 29, 2020
@Chris-Hibbert Chris-Hibbert deleted the 1829-callSpread branch October 29, 2020 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Zoe package: Zoe
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fully Collateralized Call Spread Contract
2 participants