Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
__pycache__
Manifest.toml
2 changes: 2 additions & 0 deletions Julia/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[deps]
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
100 changes: 100 additions & 0 deletions Julia/atr_risk_simulation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env julia
# ATR Risk Parameter Simulation
#
# Simulates how ATR (volatility range) and ATR_RISK_BUDGET (risk allocation %)
# drive POSITION_VALUE and STOP_RATE, and exports 2D line plots and 3D
# surface plots visualizing the results.
#
# Assumptions (not explicitly given in the PRD, confirmed with stakeholder):
# - REFERENCE_PRICE : 100,000 KRW, used to convert ATR (KRW) into a raw stop rate.
# - TOTAL_BUDGET_LIMIT: 100,000,000 KRW, the capital base for ATR_RISK_BUDGET.

using Pkg
Pkg.activate(@__DIR__)

using Plots
gr()

"Format a number with thousands separators, e.g. 10000 -> \"10,000\"."
comma_format(x) = replace(string(round(Int, x)), r"(?<=[0-9])(?=(?:[0-9]{3})+(?!\d))" => ",")

const REFERENCE_PRICE = 10_000.0 # KRW, used to convert ATR into a rate
const TOTAL_BUDGET_LIMIT = 1_000_000.0 # KRW
const MIN_STOP_RATE = 0.005 # 0.5% mandatory floor

const ATR_VALUES = 100:100:1000 # KRW, 10 points
const RISK_BUDGET_PCTS = 0.003:0.003:0.03 # fraction, 0.3%~3.0%, 10 points

"Effective stop rate: ATR normalized to REFERENCE_PRICE, floored at MIN_STOP_RATE."
effective_stop_rate(atr::Real) = max(atr / REFERENCE_PRICE, MIN_STOP_RATE)

"Position value derived from the risk budget and the effective stop rate."
function position_value(atr::Real, risk_budget_pct::Real)
risk_budget_krw = risk_budget_pct * TOTAL_BUDGET_LIMIT
return risk_budget_krw / effective_stop_rate(atr)
end

"Compute the full 10x10 grid of (stop_rate, position_value) for all ATR / risk budget combinations."
function simulate()
n_atr, n_budget = length(ATR_VALUES), length(RISK_BUDGET_PCTS)
stop_rate = Matrix{Float64}(undef, n_budget, n_atr)
pos_value = Matrix{Float64}(undef, n_budget, n_atr)
for (j, budget) in enumerate(RISK_BUDGET_PCTS), (i, atr) in enumerate(ATR_VALUES)
stop_rate[j, i] = effective_stop_rate(atr) * 100 # store as %
pos_value[j, i] = position_value(atr, budget)
end
return stop_rate, pos_value
end

"Build the 2-row multi-panel line plot (POSITION_VALUE / STOP_RATE vs ATR, grouped by risk budget)."
function plot_2d(stop_rate, pos_value)
top = plot(title="POSITION_VALUE vs ATR", xlabel="ATR (KRW)", ylabel="POSITION_VALUE (KRW)",
legend=:outertopright, legendtitle="Risk Budget", yformatter=comma_format)
bottom = plot(title="STOP_RATE vs ATR", xlabel="ATR (KRW)", ylabel="STOP_RATE (%)",
legend=:outertopright, legendtitle="Risk Budget")

for (j, budget) in enumerate(RISK_BUDGET_PCTS)
label = string(round(budget * 100, digits=1), "%")
plot!(top, ATR_VALUES, pos_value[j, :], label=label, marker=:circle, linewidth=2)
plot!(bottom, ATR_VALUES, stop_rate[j, :], label=label, marker=:circle, linewidth=2)
end

return plot(top, bottom, layout=(2, 1), size=(1000, 1200), left_margin=15Plots.mm)
end

"Build the 3D surface plots for POSITION_VALUE and STOP_RATE over the ATR x risk-budget grid."
function plot_3d(stop_rate, pos_value)
budget_pcts = RISK_BUDGET_PCTS .* 100

pos_surface = surface(ATR_VALUES, budget_pcts, pos_value,
title="POSITION_VALUE Landscape",
xlabel="ATR (KRW)", ylabel="ATR_RISK_BUDGET (%)", zlabel="POSITION_VALUE (KRW)",
color=:viridis, zformatter=comma_format, right_margin=15Plots.mm,
bottom_margin=8Plots.mm, size=(900, 700), camera=(30, 40), fillalpha=0.60)

stop_surface = surface(ATR_VALUES, budget_pcts, stop_rate,
title="STOP_RATE Landscape",
xlabel="ATR (KRW)", ylabel="ATR_RISK_BUDGET (%)", zlabel="STOP_RATE (%)",
color=:plasma, camera=(-45, 30), bottom_margin=15Plots.mm, top_margin=10Plots.mm,
size=(900, 700), guidefontsize=9, fillalpha=0.60)

return pos_surface, stop_surface
end

function main()
output_dir = joinpath(@__DIR__, "output")
mkpath(output_dir)

stop_rate, pos_value = simulate()

fig_2d = plot_2d(stop_rate, pos_value)
savefig(fig_2d, joinpath(output_dir, "atr_risk_2d.png"))

pos_surface, stop_surface = plot_3d(stop_rate, pos_value)
savefig(pos_surface, joinpath(output_dir, "atr_risk_3d_position_value.png"))
savefig(stop_surface, joinpath(output_dir, "atr_risk_3d_stop_rate.png"))

println("Saved figures to: ", output_dir)
end

main()
8 changes: 8 additions & 0 deletions Julia/install_julia.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Installs Julia via juliaup (the official Julia version manager/installer).

set -euo pipefail

curl -fsSL https://install.julialang.org | sh -s -- --yes

echo "Julia installation complete. Restart your shell or run 'source ~/.bashrc' to update PATH."
15 changes: 15 additions & 0 deletions Julia/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Runs a Julia script after sourcing ~/.bashrc so the juliaup PATH is available.

# Usage: ./run.sh filename.jl

set -euo pipefail

if [[ $# -lt 1 ]]; then
echo "Usage: $0 <filename.jl>"
exit 1
fi

source ~/.bashrc

julia --project="$(dirname "$0")" "$@"
1 change: 1 addition & 0 deletions install_antigravity_cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
curl -fsSL https://antigravity.google/cli/install.sh | bash