fork download
  1. /*
  2.  * Stock Market Trader Simulator — чистый C (C99), без C++.
  3.  * Сборка: gcc -std=c99 -O2 -o stock_trader_sim stock_trader_sim.c
  4.  * Windows (MinGW): то же самое.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <time.h>
  11.  
  12. #define MAX_SYMBOL_LEN 8
  13. #define MAX_NAME_LEN 32
  14. #define NUM_STOCKS 5
  15. #define STARTING_CASH 10000.0
  16.  
  17. typedef struct {
  18. char symbol[MAX_SYMBOL_LEN];
  19. char name[MAX_NAME_LEN];
  20. double price;
  21. double prev_price;
  22. double volatility; /* доля (например 0.02 = ±2% в среднем за день) */
  23. } Stock;
  24.  
  25. typedef struct {
  26. int shares[NUM_STOCKS];
  27. } Holdings;
  28.  
  29. static Stock market[NUM_STOCKS];
  30. static Holdings holdings;
  31. static double cash;
  32. static int day;
  33.  
  34. static void init_market(void) {
  35. const char *names[NUM_STOCKS] = {
  36. "Northern Tech Inc",
  37. "Global Ore Co",
  38. "Sunrise Pharma",
  39. "Metro Retail Group",
  40. "BlueWave Energy"
  41. };
  42. const char *syms[NUM_STOCKS] = { "NTEC", "GORE", "SPHR", "MRET", "BWVN" };
  43. double base_prices[NUM_STOCKS] = { 42.50, 18.25, 120.00, 35.80, 55.40 };
  44. double vols[NUM_STOCKS] = { 0.025, 0.035, 0.04, 0.02, 0.03 };
  45. int i;
  46.  
  47. for (i = 0; i < NUM_STOCKS; i++) {
  48. strncpy(market[i].symbol, syms[i], MAX_SYMBOL_LEN - 1);
  49. market[i].symbol[MAX_SYMBOL_LEN - 1] = '\0';
  50. strncpy(market[i].name, names[i], MAX_NAME_LEN - 1);
  51. market[i].name[MAX_NAME_LEN - 1] = '\0';
  52. market[i].price = base_prices[i];
  53. market[i].prev_price = base_prices[i];
  54. market[i].volatility = vols[i];
  55. holdings.shares[i] = 0;
  56. }
  57. }
  58.  
  59. /* Простой LCG для платформ без arc4random; достаточно для игры. */
  60. static unsigned rng_state;
  61.  
  62. static void rng_seed(void) {
  63. rng_state = (unsigned)time(NULL) ^ 0x9E3779B9u;
  64. if (rng_state == 0u) rng_state = 1u;
  65. }
  66.  
  67. static double rng_uniform(void) {
  68. /* xorshift вместо rand() для предсказуемости качества по дням */
  69. rng_state ^= rng_state << 13;
  70. rng_state ^= rng_state >> 17;
  71. rng_state ^= rng_state << 5;
  72. return (rng_state & 0xFFFFFFu) / (double)0x1000000u;
  73. }
  74.  
  75. static double rng_gaussian_approx(void) {
  76. /* Сумма 12 U(0,1) - 6 ≈ N(0,1) */
  77. double s = 0.0;
  78. int k;
  79. for (k = 0; k < 12; k++) s += rng_uniform();
  80. return s - 6.0;
  81. }
  82.  
  83. static void advance_day(void) {
  84. int i;
  85. day++;
  86. for (i = 0; i < NUM_STOCKS; i++) {
  87. double change;
  88. market[i].prev_price = market[i].price;
  89. change = rng_gaussian_approx() * market[i].volatility;
  90. market[i].price *= (1.0 + change);
  91. if (market[i].price < 0.01) market[i].price = 0.01;
  92. }
  93. }
  94.  
  95. static double portfolio_value(void) {
  96. double v = cash;
  97. int i;
  98. for (i = 0; i < NUM_STOCKS; i++)
  99. v += (double)holdings.shares[i] * market[i].price;
  100. return v;
  101. }
  102.  
  103. static void print_header(void) {
  104. printf("\n");
  105. printf("================================================================\n");
  106. printf(" БИРЖЕВОЙ СИМУЛЯТОР | День %d | Кэш: $%.2f | Всего: $%.2f\n",
  107. day, cash, portfolio_value());
  108. printf("================================================================\n");
  109. }
  110.  
  111. static void print_quotes(void) {
  112. int i;
  113. printf("\n %-6s %-22s %10s %10s %8s\n", "Тикер", "Название", "Цена", "Было", "Изм.%");
  114. printf(" ------ ---------------------- ---------- ---------- --------\n");
  115. for (i = 0; i < NUM_STOCKS; i++) {
  116. double pct = 0.0;
  117. if (market[i].prev_price > 1e-9)
  118. pct = 100.0 * (market[i].price - market[i].prev_price) / market[i].prev_price;
  119. printf(" %-6s %-22s %10.2f %10.2f %+7.2f%% [у вас: %d шт.]\n",
  120. market[i].symbol, market[i].name, market[i].price,
  121. market[i].prev_price, pct, holdings.shares[i]);
  122. }
  123. }
  124.  
  125. static void print_help(void) {
  126. printf("\n Команды:\n");
  127. printf(" buy <тикер> <кол-во> — купить\n");
  128. printf(" sell <тикер> <кол-во> — продать\n");
  129. printf(" next / n — следующий торговый день (котировки меняются)\n");
  130. printf(" portfolio / p — сводка портфеля\n");
  131. printf(" help / h — эта справка\n");
  132. printf(" quit / q — выход\n");
  133. }
  134.  
  135. static int find_stock(const char *sym) {
  136. int i;
  137. for (i = 0; i < NUM_STOCKS; i++)
  138. if (strcmp(market[i].symbol, sym) == 0) return i;
  139. return -1;
  140. }
  141.  
  142. static int parse_ticker_arg(char *arg, char *out_sym) {
  143. int j = 0;
  144. while (arg[j] && j < MAX_SYMBOL_LEN - 1) {
  145. char c = arg[j];
  146. if (c >= 'a' && c <= 'z') c = (char)(c - 'a' + 'A');
  147. out_sym[j] = c;
  148. j++;
  149. }
  150. out_sym[j] = '\0';
  151. return j > 0 ? 0 : -1;
  152. }
  153.  
  154. static int buy_shares(const char *sym, int qty) {
  155. int idx = find_stock(sym);
  156. double cost;
  157. if (idx < 0) {
  158. printf(" Неизвестный тикер: %s\n", sym);
  159. return -1;
  160. }
  161. if (qty <= 0) {
  162. printf(" Количество должно быть положительным.\n");
  163. return -1;
  164. }
  165. cost = (double)qty * market[idx].price;
  166. if (cost > cash + 1e-6) {
  167. printf(" Недостаточно средств. Нужно $%.2f, есть $%.2f\n", cost, cash);
  168. return -1;
  169. }
  170. cash -= cost;
  171. holdings.shares[idx] += qty;
  172. printf(" Куплено %d x %s по $%.2f. Итого: $%.2f. Остаток кэша: $%.2f\n",
  173. qty, sym, market[idx].price, cost, cash);
  174. return 0;
  175. }
  176.  
  177. static int sell_shares(const char *sym, int qty) {
  178. int idx = find_stock(sym);
  179. double proceeds;
  180. if (idx < 0) {
  181. printf(" Неизвестный тикер: %s\n", sym);
  182. return -1;
  183. }
  184. if (qty <= 0) {
  185. printf(" Количество должно быть положительным.\n");
  186. return -1;
  187. }
  188. if (holdings.shares[idx] < qty) {
  189. printf(" У вас только %d акций %s.\n", holdings.shares[idx], sym);
  190. return -1;
  191. }
  192. proceeds = (double)qty * market[idx].price;
  193. cash += proceeds;
  194. holdings.shares[idx] -= qty;
  195. printf(" Продано %d x %s по $%.2f. Выручка: $%.2f. Кэш: $%.2f\n",
  196. qty, sym, market[idx].price, proceeds, cash);
  197. return 0;
  198. }
  199.  
  200. static void print_portfolio(void) {
  201. int i;
  202. double equity = portfolio_value();
  203. double pnl = equity - STARTING_CASH;
  204. printf("\n --- Портфель ---\n");
  205. printf(" Кэш: $%.2f\n", cash);
  206. printf(" Стоимость акций по рынку:\n");
  207. for (i = 0; i < NUM_STOCKS; i++) {
  208. if (holdings.shares[i] == 0) continue;
  209. printf(" %-6s %4d шт. x $%-8.2f = $%.2f\n",
  210. market[i].symbol, holdings.shares[i], market[i].price,
  211. (double)holdings.shares[i] * market[i].price);
  212. }
  213. printf(" Итого активы: $%.2f\n", equity);
  214. printf(" P/L от старта ($%.0f): $%+.2f (%+.1f%%)\n",
  215. STARTING_CASH, pnl, 100.0 * pnl / STARTING_CASH);
  216. }
  217.  
  218. static void trim_newline(char *s) {
  219. size_t n = strlen(s);
  220. if (n > 0 && s[n - 1] == '\n') s[n - 1] = '\0';
  221. }
  222.  
  223. static void game_loop(void) {
  224. char line[256];
  225. char cmd[32];
  226. char arg1[32];
  227. char sym[MAX_SYMBOL_LEN];
  228. int qty;
  229. int running = 1;
  230.  
  231. rng_seed();
  232. init_market();
  233. cash = STARTING_CASH;
  234. day = 1;
  235.  
  236. printf("\nДобро пожаловать! У вас $%.0f. Торгуйте, наблюдайте за рынком.\n",
  237. STARTING_CASH);
  238. print_help();
  239.  
  240. while (running) {
  241. print_header();
  242. print_quotes();
  243. printf("\n> ");
  244. fflush(stdout);
  245. if (!fgets(line, sizeof line, stdin)) break;
  246. trim_newline(line);
  247. if (line[0] == '\0') continue;
  248.  
  249. cmd[0] = '\0';
  250. arg1[0] = '\0';
  251. qty = 0;
  252. if (sscanf(line, "%31s %31s %d", cmd, arg1, &qty) < 1) continue;
  253.  
  254. if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "q") == 0) {
  255. print_portfolio();
  256. printf("\n Конец сессии.\n");
  257. running = 0;
  258. } else if (strcmp(cmd, "help") == 0 || strcmp(cmd, "h") == 0) {
  259. print_help();
  260. } else if (strcmp(cmd, "next") == 0 || strcmp(cmd, "n") == 0) {
  261. advance_day();
  262. printf(" Новый день: %d\n", day);
  263. } else if (strcmp(cmd, "portfolio") == 0 || strcmp(cmd, "p") == 0) {
  264. print_portfolio();
  265. } else if (strcmp(cmd, "buy") == 0 || strcmp(cmd, "b") == 0) {
  266. if (parse_ticker_arg(arg1, sym) != 0 || qty <= 0) {
  267. printf(" Использование: buy <ТИКЕР> <кол-во>\n");
  268. continue;
  269. }
  270. (void)buy_shares(sym, qty);
  271. } else if (strcmp(cmd, "sell") == 0 || strcmp(cmd, "s") == 0) {
  272. if (parse_ticker_arg(arg1, sym) != 0 || qty <= 0) {
  273. printf(" Использование: sell <ТИКЕР> <кол-во>\n");
  274. continue;
  275. }
  276. (void)sell_shares(sym, qty);
  277. } else {
  278. printf(" Неизвестная команда. Введите help\n");
  279. }
  280. }
  281. }
  282.  
  283. int main(void) {
  284. game_loop();
  285. return 0;
  286. }
  287.  
Success #stdin #stdout 0.01s 5320KB
stdin
Standard input is empty
stdout
Добро пожаловать! У вас $10000. Торгуйте, наблюдайте за рынком.

  Команды:
    buy <тикер> <кол-во>   — купить
    sell <тикер> <кол-во>  — продать
    next / n               — следующий торговый день (котировки меняются)
    portfolio / p          — сводка портфеля
    help / h               — эта справка
    quit / q               — выход

================================================================
  БИРЖЕВОЙ СИМУЛЯТОР  |  День 1  |  Кэш: $10000.00  |  Всего: $10000.00
================================================================

  Тикер Название         Цена   Было Изм.%
  ------ ---------------------- ---------- ---------- --------
  NTEC   Northern Tech Inc           42.50      42.50   +0.00%  [у вас: 0 шт.]
  GORE   Global Ore Co               18.25      18.25   +0.00%  [у вас: 0 шт.]
  SPHR   Sunrise Pharma             120.00     120.00   +0.00%  [у вас: 0 шт.]
  MRET   Metro Retail Group          35.80      35.80   +0.00%  [у вас: 0 шт.]
  BWVN   BlueWave Energy             55.40      55.40   +0.00%  [у вас: 0 шт.]

>