-
Notifications
You must be signed in to change notification settings - Fork 212
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
Conversation
46a3e1d
to
a99f2c7
Compare
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
a99f2c7
to
3bc0b70
Compare
There was a problem hiding this 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
There was a problem hiding this 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
* The creatorInvitation has terms that include the amounts of the two options | ||
* as longOption and shortOption. When the creatorInvitation is exercised, the |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're right.
* + 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.) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not getInvitationDetails
?
There was a problem hiding this comment.
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) }, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
const aliceOption = await aliceSeat.getOfferResult(); | ||
t.truthy(invitationIssuer.isLive(aliceOption)); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 => { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Bob buys the Short invitation | |
// Carol buys the Short invitation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
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
74627e9
to
779b33b
Compare
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