src/Controller/EngineController.php line 339

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Component\Routing\Annotation\Route;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Doctrine\ODM\MongoDB\DocumentManager;
  9. use App\Document\Order;
  10. use App\Document\MarketOrder;
  11. use App\Document\Currencies;
  12. use App\Document\Wallet;
  13. use App\Document\Trade;
  14. use App\Document\Price;
  15. use App\Document\User;
  16. use Symfony\Contracts\Translation\TranslatorInterface;
  17. use App\Document\Setting;
  18. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  19. use Symfony\Component\Process\Exception\ProcessFailedException;
  20. use Symfony\Component\Process\Process;
  21. use KuCoin\SDK\Auth;
  22. use KuCoin\SDK\Http\SwooleHttp;
  23. use KuCoin\SDK\KuCoinApi;
  24. use KuCoin\SDK\PrivateApi\Order as KuCoinOrder;
  25. use KuCoin\SDK\PrivateApi\Account;
  26. class EngineController extends AbstractController
  27. {
  28.     private $translator;
  29.     private $doc;
  30.     public function __construct(TranslatorInterface $translatorDocumentManager $doctrine)
  31.     {
  32.         $this->translator $translator;
  33.         $this->doc $doctrine;
  34.     }
  35.     private function getLastPrice($crypto,$type='sell'): float
  36.     {
  37.         $trade $this->doc->createQueryBuilder(Price::class)
  38.             ->field('pair')->equals($crypto)
  39.             ->field('type')->equals($type)
  40.             ->getQuery()
  41.             ->getSingleResult();
  42.         return is_null($trade) ? $trade->getPrice() ;
  43.     }
  44.     #[Route('/api/order/marketsubmit'methods: ['POST'], name'order_marketsubmit')]
  45.     public function marketSubmit(Request $request): JsonResponse
  46.     {
  47.         $data json_decode($request->getContent(), false);
  48.         $user $this->getUser();
  49.         $user_id $user->getId();
  50.         $status $user->getStatus();
  51.         if ($status 1) {
  52.             $translated $this->translator->trans('your account not active');
  53.             return new JsonResponse(['status' => '400''msg' => $translated]);
  54.         }
  55.         $setting $this->doc->createQueryBuilder(Setting::class)
  56.             ->limit(1)
  57.             ->getQuery()
  58.             ->getSingleResult();
  59.         $amount floatval($data->amount);
  60.         $side $data->side;
  61.         $type $data->type;
  62.         $crypto $data->crypto;
  63.         $price $data->price;
  64.         if ($amount <= 0) {
  65.             $translated $this->translator->trans('amount must larger than 1');
  66.             return new JsonResponse(['status' => '400''msg' => $translated]);
  67.         }
  68.         $wallet_rial $this->doc->createQueryBuilder(Wallet::class)
  69.             ->field('userid')->equals($user_id)
  70.             ->field('pair')->equals("RIAL")
  71.             ->getQuery()
  72.             ->getSingleResult();
  73.         $wallet_crypto $this->doc->createQueryBuilder(Wallet::class)
  74.             ->field('userid')->equals($user_id)
  75.             ->field('pair')->equals($crypto)
  76.             ->getQuery()
  77.             ->getSingleResult();
  78.         $usdt_buy_price $setting->getUsdtpricebuy();
  79.         $usdt_sell_price $setting->getUsdtpricesell();
  80.         if ($side === 'sell' && $amount $wallet_crypto->getballance()) {
  81.             $translated $this->translator->trans('ballance is LOw');
  82.             return new JsonResponse(['status' => '400''msg' => $translated]);
  83.         }
  84.         $crypto_buy $this->getLastPrice($crypto);
  85.         $crypto_buy += (($crypto_buy 0.1) / 100);
  86.         $crypto_price_buy $crypto_buy $usdt_buy_price;
  87.         if ($type === 'limit' && $price <= 0) {
  88.             $translated $this->translator->trans('Price is Low');
  89.             return new JsonResponse(['status' => '400''msg' => $translated]);
  90.         }
  91.         // if ($type === 'limit' && !$this->isPriceWithinRange($crypto_buy, $price)) {
  92.         //     $translated = $this->translator->trans('price not correct');
  93.         //     return new JsonResponse(['status' => '400', 'msg' => $translated]);
  94.         // }
  95.         if ($type === 'market') {
  96.             $price $crypto_buy;
  97.         }
  98.         if ($side === 'buy' && ($amount $crypto_price_buy) >= $wallet_rial->getballance()) {
  99.             $translated $this->translator->trans('ballance is LOw');
  100.             return new JsonResponse(['status' => '400''msg' => $translated]);
  101.         }
  102. if ($type === 'limit') {
  103.         // Freeze funds
  104.         if ($side === 'buy') {
  105.             $wallet_rial->setballance($wallet_rial->getballance() - ($amount $crypto_price_buy));
  106.             $wallet_rial->setFrozen(($amount $crypto_price_buy) + $wallet_rial->getFrozen());
  107.         } else {
  108.             $wallet_crypto->setballance($wallet_crypto->getballance() - $amount);
  109.             $wallet_crypto->setFrozen($amount $wallet_crypto->getFrozen());
  110.             
  111.         }
  112.         
  113.         $this->doc->persist($wallet_rial);
  114.         $this->doc->persist($wallet_crypto);
  115.         $this->doc->flush();
  116.         
  117. }
  118.         
  119.         $order = new MarketOrder();
  120.         $order->setUserid($user_id);
  121.         $order->setAmount($amount);
  122.         $order->setPair($crypto);
  123.         $order->setSide($side);
  124.         $order->setType($type);
  125.         $order->setPrice($price);
  126.         $order->setTakeprofit("0");
  127.         $order->setStoploss("0");
  128.         $order->setTime(time());
  129.         $order->setFee(0);
  130.         $order->setApi('');
  131.         $order->setStatus("Pending");
  132.         $this->doc->persist($order);
  133.         $this->doc->flush();
  134.         if ($type === 'market') {
  135.             // Create an opposite order for the robot
  136.             $robot_id '666621eea320d65e3f6878ec';
  137.             // Mark the original order as filled
  138.             $order->setStatus('Filled');
  139.             $this->doc->persist($order);
  140.             $this->doc->flush();
  141.             // Create a new trade
  142.             $trade_id \Ramsey\Uuid\Uuid::uuid4()->toString(); // Generate a unique trade ID
  143.             $buy_user_id $side === 'buy' $user_id $robot_id;
  144.             $sell_user_id $side === 'sell' $user_id $robot_id;
  145.             $this->createNewTrade($buy_user_id$sell_user_id$amount$crypto,'market'$price$trade_id'Completed');
  146.             // Update wallets
  147.             $this->updateWallets($buy_user_id$sell_user_id$amount$crypto$price);
  148.         }
  149.         $translated $this->translator->trans('Order Submited');
  150.         return new JsonResponse(['status' => '200''msg' => $translated]);
  151.     }
  152.     #[Route('/api/order/cancelmarketsubmit'methods: ['POST'], name'order_cancelmarketsubmit')]
  153.     public function cancelMarketSubmit(Request $request): JsonResponse
  154.     {
  155.         $data json_decode($request->getContent(), false);
  156.         $user $this->getUser();
  157.         $order_id $data->id;
  158.         $order $this->doc->createQueryBuilder(MarketOrder::class)
  159.             ->field('id')->equals($order_id)
  160.             ->getQuery()
  161.             ->getSingleResult();
  162.         if ($order && $order->getStatus() === 'Pending') {
  163.             $this->doc->createQueryBuilder(MarketOrder::class)
  164.                 ->field('id')->equals($order_id)
  165.                 ->findAndUpdate()
  166.                 ->field('status')->set('cancel')
  167.                 ->getQuery()
  168.                 ->execute();
  169.             // Unfreeze funds
  170.             if ($order->getSide() === 'buy') {
  171.                 $wallet_rial $this->doc->createQueryBuilder(Wallet::class)
  172.                     ->field('userid')->equals($user->getId())
  173.                     ->field('pair')->equals("RIAL")
  174.                     ->getQuery()
  175.                     ->getSingleResult();
  176.                 $this->unfreezeFunds($wallet_rial$order->getAmount() * $order->getPrice());
  177.             } else {
  178.                 $wallet_crypto $this->doc->createQueryBuilder(Wallet::class)
  179.                     ->field('userid')->equals($user->getId())
  180.                     ->field('pair')->equals($order->getPair())
  181.                     ->getQuery()
  182.                     ->getSingleResult();
  183.                 $this->unfreezeFunds($wallet_crypto$order->getAmount());
  184.             }
  185.             $translated $this->translator->trans('Order Canceled');
  186.             return new JsonResponse(['status' => '200''msg' => $translated]);
  187.         }
  188.         return new JsonResponse(['status' => '400''msg' => 'Order not found or not cancelable']);
  189.     }
  190.     private function unfreezeFunds($wallet$amount)
  191.     {
  192.         $wallet->setballance($wallet->getballance() + $amount);
  193.         $wallet->setFrozen($wallet->getFrozen() - $amount);
  194.         $this->doc->persist($wallet);
  195.         $this->doc->flush();
  196.     }
  197.     private function createNewTrade($buy_user_id$sell_user_id$amount$pair $type$price$trade_id$status)
  198.     {
  199.         $trade = new Trade();
  200.         $trade->setAmount($amount);
  201.         $trade->setPair($pair);
  202.         $trade->setType($type);
  203.         $trade->setPrice($price);
  204.         $trade->setTime(time());
  205.         $trade->setStatus($status);
  206.         $trade->setFee(0);
  207.         $trade->setTradeid($trade_id);
  208.         $trade->setbuyUserid($buy_user_id);
  209.         $trade->setsellUserid($sell_user_id);
  210.         $this->doc->persist($trade);
  211.         $this->doc->flush();
  212.     }
  213.     private function createOrder($user_id$amount$pair$side$type$price$robot$status)
  214.     {
  215.         $order = new MarketOrder();
  216.         $order->setUserid($user_id);
  217.         $order->setAmount($amount);
  218.         $order->setPair($pair);
  219.         $order->setSide($side);
  220.         $order->setType($type);
  221.         $order->setPrice($price);
  222.         $order->setTakeprofit("0");
  223.         $order->setStoploss("0");
  224.         $order->setTime(time());
  225.         $order->setFee(0);
  226.         $order->setRobot($robot);
  227.         $order->setStatus($status);
  228.         $this->doc->persist($order);
  229.         $this->doc->flush();
  230.     }
  231.     private function updateOrder($order)
  232.     {
  233.         $this->doc->persist($order);
  234.         $this->doc->flush();
  235.     }
  236.     private function updateWallets($buy_user_id$sell_user_id$amount$pair$price)
  237.     {
  238.         $usdt_buy_price $this->doc->createQueryBuilder(Setting::class)
  239.             ->limit(1)
  240.             ->getQuery()
  241.             ->getSingleResult()
  242.             ->getUsdtpricebuy();
  243.         $rial_amount $amount $price $usdt_buy_price;  // Corrected calculation of rial_amount
  244.         // Update buyer's wallet
  245.         $this->addMoney($buy_user_id$pair$amount);
  246.         $this->removeMoney($buy_user_id'RIAL'$rial_amount);
  247.         // Update seller's wallet
  248.         $this->addMoney($sell_user_id'RIAL'$rial_amount);
  249.         $this->removeMoney($sell_user_id$pair$amount);
  250.     }
  251.     private function addMoney($user_id$pair$amount)
  252.     {
  253.         $wallet $this->getWallet($user_id$pair);
  254.         if ($wallet) {
  255.             $wallet->setballance($wallet->getballance() + $amount);
  256.             $this->updateWallet($wallet);
  257.         }
  258.     }
  259.     private function removeMoney($user_id$pair$amount)
  260.     {
  261.         $wallet $this->getWallet($user_id$pair);
  262.         if ($wallet) {
  263.             $wallet->setballance($wallet->getballance() - $amount);
  264.             $this->updateWallet($wallet);
  265.         }
  266.     }
  267.     private function getWallet($user_id$pair)
  268.     {
  269.         return $this->doc->createQueryBuilder(Wallet::class)
  270.             ->field('userid')->equals($user_id)
  271.             ->field('pair')->equals($pair)
  272.             ->getQuery()
  273.             ->getSingleResult();
  274.     }
  275.     private function updateWallet($wallet)
  276.     {
  277.         $this->doc->persist($wallet);
  278.         $this->doc->flush();
  279.     }
  280.     
  281.     
  282.         private function isPriceWithinRange($lastPrice$newPrice): bool
  283.     {
  284.         $minPrice $lastPrice 0.1;
  285.         $maxPrice $lastPrice 0.02;
  286.         return $newPrice >= $minPrice && $newPrice <= $maxPrice;
  287.     }
  288.     
  289. #[Route('/pub/order/matchengine'methods: ['GET'], name'trade_matchengine')]
  290. public function matchEngine(): JsonResponse
  291. {
  292.     $pairs = ["BTC""ETH""DOGE""ADA""SOL""DOT""TRX""BNB""LTC"];
  293.     foreach ($pairs as $pair) {
  294.         // Retrieve all limit buy and sell orders
  295.         $buy_limit_orders $this->getMarketOrderList($pair'buy''limit');
  296.         $sell_limit_orders $this->getMarketOrderList($pair'sell''limit');
  297.         // Get the last price of the pair
  298.         $last_price_buy round($this->getLastPrice($pair,'buy'), 6);
  299.         
  300.         $last_price_sell round($this->getLastPrice($pair), 6);
  301.         
  302.   
  303.         // Process buy limit orders
  304.         foreach ($buy_limit_orders as $buy_order) {
  305.             
  306.             if ($buy_order->getPrice() >= $last_price_buy) {
  307.                 $this->processMatchingOrder($buy_order$buy_order->getPrice());
  308.             }
  309.         }
  310.         // Process sell limit orders
  311.         foreach ($sell_limit_orders as $sell_order) {
  312.             echo "o" $sell_order->getPrice() . 'o' $last_price_sell ;
  313.             if ($sell_order->getPrice() <= $last_price_sell) {
  314.                 $this->processMatchingOrder($sell_order$sell_order->getPrice());
  315.             }
  316.         }
  317.     }
  318.     return new JsonResponse(['status' => '200''msg' => 'Match Engine Run Successfully']);
  319. }
  320. private function processMatchingOrder($order$last_price)
  321. {
  322.     $user_id $order->getUserid();
  323.     $amount $order->getAmount();
  324.     $pair $order->getPair();
  325.     $side $order->getSide();
  326.     $opposite_side $side === 'buy' 'sell' 'buy';
  327.     $robot_id '666621eea320d65e3f6878ec';
  328.     // Create an opposite order for the robot
  329.     $this->createOrder($robot_id$amount$pair$opposite_side'market'$last_pricetrue'Filled');
  330.     // Mark the original order as filled
  331.     $order->setStatus('Filled');
  332.     $this->updateOrder($order);
  333.         $setting $this->doc->createQueryBuilder(Setting::class)
  334.             ->limit(1)
  335.             ->getQuery()
  336.             ->getSingleResult();
  337.         $usdt_buy_price $setting->getUsdtpricebuy();
  338.         $usdt_sell_price $setting->getUsdtpricesell();
  339.         $crypto_price_buy $this->getLastPrice($pair 'buy') ;
  340.         $crypto_price_sell $this->getLastPrice($pair) ;
  341.         
  342.     // Create a new trade
  343.     $trade_id \Ramsey\Uuid\Uuid::uuid4()->toString();
  344.     $buy_user_id $side === 'buy' $user_id $robot_id;
  345.     $sell_user_id $side === 'sell' $user_id $robot_id;
  346.     $this->createNewTrade($buy_user_id$sell_user_id$amount$pair ,'limit'$last_price$trade_id'Completed');
  347.     
  348.     
  349.               $wallet_rial $this->doc->createQueryBuilder(Wallet::class)
  350.                     ->field('userid')->equals($user_id)
  351.                     ->field('pair')->equals("RIAL")
  352.                     ->getQuery()
  353.                     ->getSingleResult();
  354.                     
  355.                     
  356.             $wallet_crypto $this->doc->createQueryBuilder(Wallet::class)
  357.                     ->field('userid')->equals($user_id)
  358.                     ->field('pair')->equals($order->getPair())
  359.                     ->getQuery()
  360.                     ->getSingleResult();
  361.     
  362.     
  363.                if ($order->getSide() === 'buy') {
  364.       
  365.                     
  366.                $wallet_rial->setFrozen(  $wallet_rial->getFrozen()  - (($amount $crypto_price_buy) * $usdt_buy_price) );
  367.                $wallet_crypto->setballance($wallet_crypto->getballance() + $amount);
  368.                
  369.             } else {
  370.              
  371.                 $wallet_crypto->setFrozen$wallet_crypto->getFrozen() - $amount);
  372.                 $wallet_rial->setballance($wallet_rial->getballance() + (($amount $crypto_price_buy) * $usdt_buy_price));
  373.      
  374.    
  375.             }
  376.                  $this->updateWallet($wallet_rial);
  377.                 $this->updateWallet($wallet_crypto);
  378.     // Update wallets
  379.   //  $this->updateWallets($buy_user_id, $sell_user_id, $amount, $pair, $last_price);
  380. }
  381.     
  382.         private function getMarketOrderList($pair$side$type)
  383.     {
  384.         return $this->doc->createQueryBuilder(MarketOrder::class)
  385.             ->field('side')->equals($side)
  386.             ->field('type')->equals($type)
  387.             ->field('status')->equals('Pending')
  388.             ->field('pair')->equals($pair)
  389.          
  390.             ->limit(2000)
  391.             ->sort('time''asc')
  392.             ->getQuery()
  393.             ->execute();
  394.     }
  395.     
  396. }