Physics-Informed Neural Networks for Options Pricing
PINN-дерді туынды құралдарға қолданудың қызықты бөлігі Black-Scholes емес. Black-Scholes-тің жабық формасы бар, сондықтан оны қайталайтын желі нәтиже емес, тек sanity check. Қызықты бөлік — жабық формасы жоқ және ақырлы айырмалар тұйыққа тірелетін жағдайлардың бәрі: аралас туындысы бар Heston-ның екі факторлы PDE-і, американдық опционның еркін шекаралы есебі және интегралдық мүшесі облыстағы әр нүктені барлық басқа нүктелермен байланыстыратын Merton-ның ішінара интегро-дифференциалдық теңдеуі.
Бұл жазбада осының әрқайсысы loss функциясына қалай енгізілетіні түсіндіріледі. Нақтырақ айтқанда: Black-Scholes PINN-ін үйретуге мүмкіндік беретін лог-баға қалдығы, cross-derivative-і autograd арқылы автоматты түрде шығатын үш кірісті Heston желісі, мерзімінен бұрын орындауды penalty мен екі желі арқылы өңдеу және jump интегралын PDE қалдығына енгізетін Gauss-Hermite квадратурасы.
Бұл benchmark емес. Төменде нәтижеге ұқсайтын әрбір сан не мақсатты көрсеткіш, не сілтеме, әрі солай белгіленген. Өлшеу кезеңінің ауқымы соңында берілген.
PINN-дерді Raissi және басқалар (2019) енгізген, ал механикасы бұл блогта Navier–Stokes есебі мақаласында қамтылған. Онда дәл сол autograd-қалдық тәсілі сұйықтық теңдеулеріндегі сингулярлықтарды іздейді: PDE loss мүшесіне айналады, autodiff желінің кірістеріне қатысты дәл туындыларды береді және тор мүлде құрылмайды. Мұндағы жалғыз өзгеріс — loss ішіне қай PDE кіретіні.
Black-Scholes PDE-і физикалық шектеу ретінде

Black-Scholes PDE-і, оның терминалдық payoff-ы және оның негізіндегі арбитражсыздық дәлелі Black-Scholes формуласы мақаласында қамтылған. Бұл бөлім соларды алғышарт деп қабылдап, желіге іс жүзінде үйретуге болатын түрге бірден өтеді.
Лог-баға түрлендіруі
-пен тікелей жұмыс істеу проблемалы: облыс , ал PDE-нің коэффициенттері айнымалы. Стандартты түрлендіруі оны тұрақты коэффициентті түрге келтіреді:
Бұл облысындағы convection-diffusion-reaction теңдеуі. және айнымалы коэффициенттері жоғалады, бұл желі үшін маңызды: шамасы -пен масштабталатын қалдық облыстың алыс шетіндегі мәндермен басым болып, оптимизатор өз бюджетін сол жерге жұмсайды.
Black-Scholes үшін PINN loss-ы
желі болсын. Ішкі облыстан коллокациялық нүктені , шекаралардан нүктені және терминалдық уақыттан нүктені аламыз:
Әрбір дербес туынды create_graph=True арқылы torch.autograd.grad көмегімен есептеледі, сондықтан backpropagation кезінде градиенттер туынды есептеу графы арқылы өтеді. Осы жалғыз flag — іске асырудағы негізгі амал.
PyTorch арқылы іске асыру

Төмендегі параметрлер оқулықтағы емес, криптоға бейімделген: акциялар үстеліндегі , орнына және (шамамен 30 күндік BTC опционы)。Қысқа өтеу мерзімі мен жоғары құбылмалылық payoff иінінің ең өткір болатын және PINN-ді үйрету ең қиын режимі — мақсат та осы.
import torch
import torch.nn as nn
import numpy as np
r = 0.05 # risk-free rate
sigma = 0.7 # volatility
K = 1.0 # strike (moneyness-normalized)
T = 0.08 # ~30 days
x_min, x_max = -1.0, 1.0 # log-price domain (S/K in [0.37, 2.72])
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
class BSPINN(nn.Module):
"""Physics-Informed Neural Network for Black-Scholes PDE."""
def __init__(self, hidden_dim=128, num_layers=4):
super().__init__()
layers = [nn.Linear(2, hidden_dim), nn.Tanh()]
for _ in range(num_layers - 1):
layers += [nn.Linear(hidden_dim, hidden_dim), nn.Tanh()]
layers.append(nn.Linear(hidden_dim, 1))
self.net = nn.Sequential(*layers)
def forward(self, x, t):
inputs = torch.cat([x, t], dim=1)
return self.net(inputs)
def compute_pde_residual(model, x, t):
"""Compute Black-Scholes PDE residual using autodiff."""
x.requires_grad_(True)
t.requires_grad_(True)
u = model(x, t)
grads = torch.autograd.grad(u, [x, t], grad_outputs=torch.ones_like(u),
create_graph=True)
u_x, u_t = grads[0], grads[1]
u_xx = torch.autograd.grad(u_x, x, grad_outputs=torch.ones_like(u_x),
create_graph=True)[0]
residual = u_t + 0.5 * sigma**2 * u_xx + (r - 0.5 * sigma**2) * u_x - r * u
return residual
def terminal_condition(x):
"""European call payoff: max(S - K, 0) = max(exp(x) - K, 0)."""
return torch.relu(torch.exp(x) - K)
def train_pinn(epochs=10000, lr=1e-3, n_interior=5000, n_boundary=500, n_terminal=1000):
model = BSPINN().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs)
for epoch in range(epochs):
optimizer.zero_grad()
x_int = (torch.rand(n_interior, 1, device=device)
* (x_max - x_min) + x_min)
t_int = torch.rand(n_interior, 1, device=device) * T
residual = compute_pde_residual(model, x_int, t_int)
loss_pde = (residual ** 2).mean()
x_tc = (torch.rand(n_terminal, 1, device=device)
* (x_max - x_min) + x_min)
t_tc = torch.ones(n_terminal, 1, device=device) * T
u_tc = model(x_tc, t_tc)
loss_ic = ((u_tc - terminal_condition(x_tc)) ** 2).mean()
t_bc = torch.rand(n_boundary, 1, device=device) * T
x_lo = torch.full((n_boundary, 1), x_min, device=device)
loss_bc_lo = (model(x_lo, t_bc) ** 2).mean()
x_hi = torch.full((n_boundary, 1), x_max, device=device)
target_hi = torch.exp(x_hi) - K * torch.exp(-r * (T - t_bc))
loss_bc_hi = ((model(x_hi, t_bc) - target_hi) ** 2).mean()
loss = loss_pde + 10.0 * loss_ic + loss_bc_lo + loss_bc_hi
loss.backward()
optimizer.step()
scheduler.step()
if epoch % 1000 == 0:
print(f"Epoch {epoch:5d} | PDE: {loss_pde:.2e} | "
f"IC: {loss_ic:.2e} | BC: {loss_bc_lo + loss_bc_hi:.2e}")
return model
Екі құрылымдық шешімге назар аудару керек:
- Терминалдық шарттың салмағы. Payoff есепті анықтайтындықтан оған 10 есе салмақ берілген. Күшті бекіту болмаса, желі барлық жерде нөл шығарып, PDE-ні тривиалды түрде қанағаттандыра алады — біртекті PDE-нің шешімдері шексіз көп, ал терминалдық шарт солардың біреуін таңдайды.
- Коллокациялық нүктелерді әр эпохада қайта іріктеу. Нүктелер әр қадамда жаңадан алынады, бұл қалдыққа стохастикалық регуляризация ретінде әсер етеді. Баламасы — бекітілген нүктелер жиыны: ол желіге дәл сол координаттардағы қалдықты артық үйренуге мүмкіндік береді.
Heston стохастикалық құбылмалылық моделіне кеңейту

Black-Scholes бір тұрақты -мен баға қояды, ал бұл дәл GARCH(1,1) құбылмалылығын болжау жоққа шығаруға арналған болжам. Heston құбылмалылықты екінші стохастикалық фактор — лездік дисперсия ретінде енгізеді:
мұнда — ортаға қайту жылдамдығы, — ұзақ мерзімді дисперсия, — vol-of-vol, ал .
Баға қою PDE-і күй кеңістігінде екі өлшемді:
Meshfree әдісі дәл осы жерде тартымды бола бастайды. Ақырлы айырмалар схемасына бойынша тор қажет — мысалы, торы түйіннен тұрады. Стохастикалық мөлшерге пайыздық мөлшерлеме сияқты үшінші факторды қоссаңыз, тор практикалық болмай қалады. Монте-Карло өлшемділікте жақсырақ масштабталады, бірақ әсіресе Greeks үшін баяу жинақталады.
Heston үшін PINN архитектурасы
Желі болатын үш кірісті қабылдайды. ADI схемаларын күрделендіретін аралас туындысы — тағы бір autograd.grad шақыруы ғана:
class HestonPINN(nn.Module):
def __init__(self, hidden_dim=256, num_layers=5):
super().__init__()
layers = [nn.Linear(3, hidden_dim), nn.Tanh()]
for _ in range(num_layers - 1):
layers += [nn.Linear(hidden_dim, hidden_dim), nn.Tanh()]
layers.append(nn.Linear(hidden_dim, 1))
self.net = nn.Sequential(*layers)
def forward(self, x, v, t):
return self.net(torch.cat([x, v, t], dim=1))
def heston_pde_residual(model, x, v, t, kappa, theta, xi, rho, r):
x.requires_grad_(True)
v.requires_grad_(True)
t.requires_grad_(True)
u = model(x, v, t)
u_x, u_v, u_t = torch.autograd.grad(
u, [x, v, t], torch.ones_like(u), create_graph=True
)
u_xx = torch.autograd.grad(u_x, x, torch.ones_like(u_x), create_graph=True)[0]
u_vv = torch.autograd.grad(u_v, v, torch.ones_like(u_v), create_graph=True)[0]
u_xv = torch.autograd.grad(u_x, v, torch.ones_like(u_x), create_graph=True)[0]
residual = (
u_t
+ 0.5 * v * u_xx
+ rho * xi * v * u_xv
+ 0.5 * xi**2 * v * u_vv
+ (r - 0.5 * v) * u_x
+ kappa * (theta - v) * u_v
- r * u
)
return residual
u_xv бірінші шақыруда құрылған графты қайта пайдаланып, u_x-ті бойынша дифференциалдау арқылы алынады. Аралас туындының симметриясы бойынша u_v-ті бойынша дифференциалдау сол тензорды беруі керек. Бірақ float32-де ол дәл бірдей болмайды, ал айырма графтың дұрыс жұмыс істеп тұрғанын тексеретін арзан диагностика болады.
Америкалық опциондар және еркін шекара есептері

Америкалық опциондар мерзімінен бұрын орындау шектеуін қосады: құн ішкі құннан ешқашан төмен түспеуі керек. Бұл PDE-ні еркін шекара есебіне, баламалы түрде сызықтық толықтыру есебіне(LCP)айналдырады:
мұнда — Black-Scholes операторы, ал — payoff. Мұны loss-қа енгізудің екі жолы бар.
Penalty әдісі
Толықтыру шектеуін тегіс penalty арқылы алмастырамыз:
мұнда үлкен болады(әдетте пен арасы)。 ішкі құннан төмендегенде penalty оны қайта көтереді, ал PINN loss-ы мынаған айналады:
Архитектура өзгермейді, тек қалдық өзгереді. Бағасы — шарттау жағынан қолайсыз жаңа гиперпараметр: тым кіші болса шектеу бұзылады, тым үлкен болса loss ландшафтында penalty мүшесі үстемдік етеді.
Тікелей еркін шекара тәсілі
Екі желіні бірге үйретеміз: біреуі бағаға , екіншісі оңтайлы орындау шекарасына жауап береді. Loss жалғастыру аймағындағы PDE-ні, шекарадағы smooth-pasting шартын және орындау аймағындағы payoff-ты қамтиды. Шекара бірінші класты шығыс ретінде пайда болады, ал америкалық опциондар кітабын хеджирлеу үшін шын мәнінде қажет нәрсе осы.
PINN-дермен jump-diffusion модельдері

Merton моделі геометриялық Броун қозғалысына Пуассон секірістерін қосады:
мұнда — интенсивтілігі болатын және өлшемдері log-normal үлестірілген compound Poisson процесі. Баға қою partial integro-differential equation(PIDE)түріне өтеді:
мұнда — jump multiplier тығыздығы.
Интеграл ақырлы айырмаларды бұзатын нәрсе: ол облыстағы әр нүктені барлық басқа нүктелермен байланыстырып, solver сүйенетін banded құрылымды жояды. PINN-де жоғалтатын мұндай құрылым жоқ. Интеграл қалдықтағы тағы бір мүше ғана; ол әр коллокациялық нүктеде квадратурамен есептеледі және желі барлық жерде анықталғандықтан, интерполяция емес, еркін forward pass болады:
def jump_integral(model, x, t, lam, mu_j, sigma_j, n_quad=32):
"""Approximate jump integral using Gauss-Hermite quadrature."""
nodes, weights = np.polynomial.hermite.hermgauss(n_quad)
nodes = torch.tensor(nodes, dtype=torch.float32, device=x.device)
weights = torch.tensor(weights, dtype=torch.float32, device=x.device)
y_nodes = mu_j + sigma_j * np.sqrt(2) * nodes
integral = torch.zeros_like(x)
for i in range(n_quad):
x_shifted = x + y_nodes[i]
v_shifted = model(x_shifted, t)
integral += weights[i] * v_shifted
integral *= 1.0 / np.sqrt(np.pi)
return integral
Содан кейін PIDE қалдығы мынадай болады:
мұнда — квадратуралық жуықтау. Цикл әр оқыту қадамына n_quad қосымша forward pass қосады және олардың бәрі autograd графына түседі — jump-тердің шын бағасы математика емес, жад.
Дәстүрлі әдістермен салыстыру

Құрылымдық айырмашылықтар шынайы және benchmark-сыз да сипатталады:
| Критерий | Ақырлы айырмалар | Монте-Карло | PINN |
|---|---|---|---|
| Тор қажет пе | Иә(құрылымдық тор) | Жоқ | Жоқ(торсыз) |
| Өлшемділік қарғысы | Қатты(>3D практикалық емес) | Әлсіз( жинақталуы) | Әлсіз(желі сыйымдылығы масштабталады) |
| Greeks | Ақырлы айырма жуықтауы | Pathwise/LR бағалаушылары | Autodiff арқылы дәл |
| Параметрлер арасында қайта пайдалану | Қайта шешу керек | Қайта симуляциялау керек | Параметрлік: бір рет үйрету |
| Америкалық опциондар | LCP-дегі SOR/PSOR | Longstaff-Schwartz регрессиясы | Penalty немесе еркін шекара |
| Қате шектері | Иә(схема реті) | Иә(CLT) | Жоқ — тек эмпирикалық loss |
Әдетте мұнда тұратын өнімділік жолдары — оқыту уақыты, инференс кідірісі, дәлдік — әдейі жоқ. Өйткені оларды өлшеу ашық жұмыс, кесте жолы емес.
PINN-дер қай жерде ұтуы мүмкін
Нақты уақыттағы қайта бағалау. Үйретілгеннен кейін бағалау batch бойынша бір forward pass болғандықтан, бүкіл кітап әр параметр жиыны үшін жеке solve орнына бір kernel launch арқылы қайта бағаланады. Бұл шынайы кітап өлшемдерінде жақсы бапталған Crank-Nicolson solver-ден оза ма — эмпирикалық әрі бұл жерде өлшенбеген сұрақ.
Жоғары өлшемді модельдер. Стохастикалық құбылмалылыққа стохастикалық мөлшерлеме мен jump қосылса, өлшем 4 немесе одан көп болады және ақырлы айырмалар іс жүзінде жарамсыз. PINN-дер оқыту қиындығы шегінде өлшем артқанда біртіндеп нашарлайды.
Үздіксіз Greeks. Желі тегіс әрі дифференциалданатын болғандықтан, Delta, Gamma, Theta және Vega PDE қалдығымен бірдей autograd механизмінен шығады — bump-and-revalue де, ақырлы айырма шуы да жоқ. Бұл жазбадағы ең күшті тұжырым және сонымен бірге артында өлшенген Gamma беті ең қажет тұжырым.
Параметрлік шешімдер. Модель параметрлерін(, , )желі кірісі ретінде беру бір PINN-ге бір калибрлеуді емес, модельдер отбасын қамтуға мүмкіндік береді.
PINN-дер қай жерде қиналады
Оқыту құны. Бір параметр жиынындағы бір опцион үшін ақырлы айырма шешімі PINN алғашқы мың эпохасын аяқтағанша әлдеқашан бітіп қалады.
Қате шектері жоқ. Richardson экстраполяциясы бар ақырлы айырмалар белгілі жинақталу ретімен машиналық дәлдікке жетеді. PINN loss мәнін береді, ал ол қате шегі емес. Белгісіздікті ескеретін варианттар(Bai және басқалар, 2025)сенім интервалдарын қосады, бірақ бұл сала әлі жас.
Оңтайландыру қиындығы. Loss ландшафты өте бейдөңес, ал PDE, шекара және терминал мүшелерінің салмақтарын теңестіру — tuning мәселесі. Әдеттегі сәтсіздік — PDE қалдығын нөлге жақындатқанымен, шекара шарттарын толық елемейтін желі. Бұл қате есептің мінсіз жарамды шешімі.
Қайта өндірілуі. Әртүрлі seed, коллокация үлестірімдері және optimizer баптаулары мағыналы түрде әртүрлі шешімдерге әкелуі мүмкін. Ансамбльдеу көмектеседі және құнды көбейтеді.
Соңғы екі тармақты графикке айналдыру бұл жазбадағы ең пайдалы жұмыс болуы мүмкін, өйткені осы кодты қайта іске асырған кез келген адам дәл осы сәтсіздік режимдеріне тап болады.
Әлі өлшеуді қажет ететін нәрселер

Бұл мақаланың адал күйі мынадай: тұжырымдар дұрыс, код орындалады, бірақ мұндағылардың ешқайсысы осы үстелдің жабдығында немесе осы үстелдің деректерінде benchmark-тан өтпеген. Оны туындыдан нәтижеге айналдыратын өлшеу кезеңі:
- Жабық формалы Black-Scholes-ке қарсы sup-norm және RMSE торында, әр seed үшін бес seed. Әдеттегі ауызша мақсат — 4 немесе одан көп ондық таңбаға дейін сәйкесу; міндет , кезінде осыны тексеріп, қай seed-терде сәтсіз болғанын жариялау.
- Тек баға қатесін емес, Delta мен Gamma қатесін өлшеу. Бағаны төрт ондыққа дейін қайталайтын, бірақ -сы шулы желі хеджирлеуге жарамсыз, сондықтан Gamma — қабылдау критерийі.
- 10 000 опциондық кітап үшін қабырға сағатымен оқыту уақыты мен бір опционның инференс кідірісі, дәл сол GPU-да дәл сол есептің Crank-Nicolson шешімімен салыстыру.
- Сәтсіздік режимдерін әдейі қайталау. Желі PDE-ні қанағаттандырып, шекараны өткізіп жібергенше boundary loss салмағын азайту; бес seed іске қосып, айырманы графикке түсіру. Екеуін де жасау арзан әрі тағы бір дұрыс көрінетін баға бетінен пайдалырақ.
- Нақты Deribit BTC котировкаларына бейімдеу, немесе кем дегенде жоғарыдағы криптоға шынайы параметрлерді , мәндеріне қайтармай сақтау.
- Архитектура мен optimizer таңдауларын кеңес емес, нәтиже ретінде көрсету. Кеңірек пен тереңірек,
tanhпен ReLU(ReLU-дің үзілісті екінші туындысы қалдықты көзге көрінерліктей бұзуы керек), sweep-тері және Adam-нан кейін L-BFGS қолдану мен тек Adam арасындағы айырма — бәрі бір жолдық эксперимент. Олар іске қосылмайынша, әдебиеттен қайталанған аңыз ғана, сондықтан бұл жазба оларды ұсыныс ретінде қайталамайды.
Өлшеусіз де сақталатын екі құрылымдық тұжырым бар, өйткені олар іске қосу нәтижесіне емес, тұжырымның қасиеттеріне жатады: лог-баға координаталарын пайдалану(PDE тұрақты коэффициентті болады, бұл алгебра фактісі)және терминалдық шартқа PDE мүшесінен жоғары салмақ беру(біртекті PDE нөлдік шешімге жол береді, бұл есептің фактісі)。
Тағы не бар

Төмендегілердің ешқайсысы мұнда тексерілмеген, бірақ білуге тұрарлық бағыттар:
- Residual-adaptive коллокация үлгілеуі — нүктелерді біркелкі емес, қалдық үлкен жерлерге: Black-Scholes үшін strike маңына немесе Heston үшін Feller шекарасына орналастыру. Іске асыруы қысқа:
def adaptive_resample(model, x_pool, t_pool, n_select):
"""Select collocation points with highest PDE residual."""
with torch.no_grad():
residuals = compute_pde_residual(model, x_pool, t_pool).abs()
probs = residuals.squeeze() / residuals.sum()
indices = torch.multinomial(probs, n_select, replacement=False)
return x_pool[indices], t_pool[indices]
- Strike пен өтеу мерзімдері арасында transfer learning — нөлден оқытудың орнына көршілес мәндерінен fine-tune жасап, опциондар тізбегін қамтитын кітапхана ұстау.
- Physics-Informed Extreme Learning Machines — жасырын салмақтарды бекітіп, тек шығу қабатын үйрету, яғни оқытуды бір сызықтық шешімге дейін қысқарту. Өрнектеу қабілеті төмен, бірақ Black-Scholes өлшемі аз болғандықтан бұл маңызды болмауы мүмкін.
- Operator learning(DeepONet, FNO) — шешімнің өзін емес, шешім операторын үйрену. бейнелеуі арқылы жаңа payoff құрылымдары қайта оқытуды қажет етпейді. DeepSVM мақаласын қараңыз.
Қорытынды

PINN-дер ақырлы айырмаларды да, Монте-Карлоны да алмастырмайды. Бір параметр жиынындағы бір төмен өлшемді опцион үшін ақырлы айырмалар жеңеді және айырма аз емес. PINN-дерге арналған жағдай тар әрі нақты: торлар жарамсыз болатын жоғары өлшемді модельдер, кітап бойынша қайта пайдаланылатын параметрлік шешімдер және бағамен бір autodiff қадамынан шығатын Greeks.
Бұл жазба ұсынатыны — аударма қабаты: Heston-ның аралас туындысы, америкалық опционның еркін шекарасы және Merton jump интегралы loss функциясының мүшесіне қалай айналады. Әзірге ұсынбайтыны — нәтижелік желілердің хеджирлеуге жеткілікті дәл екеніне дәлел. Бұл келесі кезеңнің жұмысы, ол орындалғанша жоғарыдағының бәрін ұсыныс емес, туынды ретінде қабылдаңыз.
Сілтемелер және қосымша оқу
- Raissi, M., Perdikaris, P., Karniadakis, G.E. (2019). Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations. Journal of Computational Physics, 378, 686-707.
- Dhiman, A., Kaur, D. (2023). Physics Informed Neural Network for Option Pricing. arXiv preprint.
- Salvador, B. et al. (2023). Meshless methods for American option pricing through Physics-Informed Neural Networks. Engineering Analysis with Boundary Elements.
- Bai, G. et al. (2025). An uncertainty-aware physics-informed neural network solution for the Black-Scholes equation. arXiv preprint.
- Chen, Y. et al. (2025). Stochastic jump diffusion process informed neural networks for American option pricing under data scarcity. Applied Soft Computing.
- Benth, F.E. et al. (2025). DeepSVM: Learning Stochastic Volatility Models with Physics-Informed Deep Operator Networks. arXiv preprint.
- He, Y. et al. (2024). Finance-Informed Neural Network: Learning the Geometry of Option Pricing. arXiv preprint.
- MathWorks: Physics-Informed Neural Networks (PINNs) for Option Pricing. MATLAB Finance Blog, 2025.
- GitHub: BlackScholesPINN (PyTorch implementation).
- Raissi PINNs GitHub repository.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.