Skip to content

Commit

Permalink
ema spec
Browse files Browse the repository at this point in the history
  • Loading branch information
micahkendall committed Sep 5, 2024
1 parent 5dc11e6 commit 3b455e7
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 0 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Build

on:
workflow_dispatch:
push:
branches: ["main"]
tags: ["v*.*.*"]
pull_request:
branches: ["main"]

permissions:
contents: write

jobs:
build:
runs-on: macos-latest
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v3

- name: 🧰 Download Typst
uses: robinraju/release-downloader@v1.7
with:
repository: typst/typst
tag: v0.10.0
fileName: typst-x86_64-apple-darwin.tar.xz

- name: 🧰 Extract Typst
shell: bash
run: |
sudo mkdir /usr/local/typst
sudo tar -xzf typst-x86_64-apple-darwin.tar.xz -C /usr/local/typst/
rm -f typst-x86_64-apple-darwin.tar.xz
echo "/usr/local/typst/typst-x86_64-apple-darwin" >> $GITHUB_PATH
- run: "echo $GITHUB_SHA > ./version.txt"

- name: 📘 Compile
shell: bash
run: ./build.sh

- name: 📦 Upload artifacts
uses: actions/upload-artifact@v3
with:
name: oracle_spec
path: ./*.pdf

- name: 🚀 Release
uses: softprops/action-gh-release@v1
if: github.ref_type == 'tag'
with:
name: ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
files: "./*.pdf"

- run: "mkdir output && mv spec.pdf output/spec.pdf"

- name: Publish
uses: ryand56/r2-upload-action@latest
with:
r2-account-id: ${{ secrets.R2_ACCOUNT_ID }}
r2-access-key-id: ${{ secrets.R2_ACCESS_KEY_ID }}
r2-secret-access-key: ${{ secrets.R2_SECRET_ACCESS_KEY }}
r2-bucket: ${{ secrets.R2_BUCKET }}
source-dir: output
destination-dir: ./
Binary file added img/example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/logo-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions oracles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import matplotlib.pyplot as plt
import numpy as np

def generate_price_data(initial_price, num_days, volatility):
"""Generate price data using random walk."""
prices = [initial_price]
for _ in range(num_days - 1):
change = np.random.normal(0, volatility)
new_price = max(0, prices[-1] + change) # Ensure price doesn't go negative
prices.append(new_price)
return prices

def calculate_modified_ema(prices, period=20):
"""Calculate Modified Exponential Moving Average."""
ema = [prices[0]]
multiplier = 2 / (period + 1)
for price in prices[1:]:
if price < ema[-1]:
ema.append(price) # Immediately adjust to price decrease
else:
ema.append((price - ema[-1]) * multiplier + ema[-1]) # Use EMA for price increase
return ema

def calculate_simple_ema(prices, period=20):
"""
Calculate Simple Exponential Moving Average with immediate price decrease reflection.
This is the preferred model for our analysis. It has the following characteristics:
1. Immediately adjusts to price decreases, providing quick responsiveness to market downturns.
2. Uses standard EMA calculation for price increases, allowing for a smoother trend during upward movements.
This combination allows for quick reaction to potential losses while maintaining trend stability during growth periods.
"""
ema = [prices[0]]
multiplier = 2 / (period + 1)
for price in prices[1:]:
if price < ema[-1]:
ema.append(price) # Immediately adjust to price decrease
else:
ema.append((price - ema[-1]) * multiplier + ema[-1]) # Use EMA for price increase
return ema

def plot_asset_price(asset_name, initial_price=100, num_days=365, volatility=1):
"""Plot the price of an asset over time."""
days = range(num_days)
prices = generate_price_data(initial_price, num_days, volatility)
simple_ema = calculate_simple_ema(prices)

plt.figure(figsize=(10, 6))
plt.plot(days, prices, label='Price')
plt.plot(days, simple_ema, label='Simple EMA (Preferred Model)', color='red')
plt.title(f"Price of {asset_name} Over Time")
plt.xlabel("Days")
plt.ylabel("Price")
plt.grid(True)
plt.legend()
plt.savefig('img/example.png')
plt.close()

# Example usage
plot_asset_price("XYZ", initial_price=100, num_days=365, volatility=1)
84 changes: 84 additions & 0 deletions spec.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#let special_version = read("./version.txt")
#align(center, [
#v(2em)
#[#set par(justify: true)
#image("img/logo-black.png", width: 120pt)]
#set text(size:18pt)

Oracle Specifications
#align(center, text(12pt, weight: 400)[
v. #special_version
])

#datetime.today().display("[day] [month repr:long], [year]")
])
#v(2em)
= Simple EMA Oracle Specification

== Overview
This specification outlines the Simple Exponential Moving Average (EMA) oracle algorithm, which is designed to provide a responsive and adaptive measure of asset price trends. The algorithm is particularly suited for financial applications where quick reactions to market downturns are crucial while maintaining stability during upward trends.

== Algorithm Description
The Simple EMA algorithm uses a single piece of previous state to add a drag for any price increases while immediately reflecting price decreases. This approach combines the benefits of quick responsiveness to potential losses with the stability of trend following during growth periods.

== Key Features
1. Immediate reflection of price decreases
2. Smoothed response to price increases using EMA calculation
3. Single state variable for efficient implementation

== Implementation Details

=== Inputs
- `prices`: A list of asset prices over time
- `period`: The number of days for the EMA calculation (default: 20)

=== Output
- A list of EMA values corresponding to the input prices

== Visual Representation

The following graph illustrates the behavior of the Simple EMA algorithm compared to the actual price of an asset over time:

#figure(
image("img/example.png", width: 80%),
caption: [
Comparison of Asset Price and Simple EMA over time.
The red line represents the Simple EMA, which quickly adapts to price decreases while smoothing price increases.
]
)

This visual representation demonstrates how the Simple EMA (red line) closely follows the asset price (blue line) during downward movements, while providing a smoother trend during upward movements. This behavior aligns with the algorithm's design to be responsive to potential losses while maintaining stability during growth periods.


=== Pseudocode

#figure([
#set text(font: "New Computer Modern Mono")

*Input:* prices, period \
*Output:* ema

ema \<\- [prices[0]] \
multiplier \<\- 2 / (period + 1)

*for* price *in* prices[1:] \
#h(20pt)*if* price < ema[-1] \
#h(40pt)ema.append(price) \
#h(20pt)*else* \
#h(40pt)new_ema \<\- (price - ema[-1]) \* multiplier + ema[-1] \
#h(40pt)ema.append(new_ema) \
#h(20pt)*end if* \
*end for*

*return* ema
], caption: "Simple EMA Algorithm")

== Notes
1. The algorithm initializes the EMA with the first price in the series.
2. For each subsequent price:
- If the new price is lower than the previous EMA, it immediately becomes the new EMA value.
- If the new price is higher, a standard EMA calculation is applied.
3. This approach ensures quick adaptation to price drops while smoothing out price increases.

== Reference Implementation
For a reference implementation, refer to the `calculate_simple_ema` function in the `oracles.py` file.
1 change: 1 addition & 0 deletions version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DEV VERSION

0 comments on commit 3b455e7

Please sign in to comment.