bencagri /
mokka
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Mokka\Command; |
||
| 4 | |||
| 5 | |||
| 6 | use Mokka\Action\Action; |
||
| 7 | use Mokka\Action\ActionInterface; |
||
| 8 | use Mokka\Action\BuyAction; |
||
| 9 | use Mokka\Action\SellAction; |
||
| 10 | use Mokka\Calculator\Quantity; |
||
| 11 | use Mokka\Config\Configurator; |
||
| 12 | use Mokka\Config\Logger; |
||
| 13 | use Mokka\Exchange\ExchangeFactory; |
||
| 14 | use Mokka\Strategy\IndicatorFactory; |
||
| 15 | use Mokka\Strategy\StrategyCalculator; |
||
| 16 | use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; |
||
| 17 | use Symfony\Component\Console\Command\Command; |
||
| 18 | use Symfony\Component\Console\Helper\Table; |
||
| 19 | use Symfony\Component\Console\Input\InputInterface; |
||
| 20 | use Symfony\Component\Console\Input\InputOption; |
||
| 21 | use Symfony\Component\Console\Output\OutputInterface; |
||
| 22 | use Symfony\Component\Console\Question\ChoiceQuestion; |
||
| 23 | use Symfony\Component\Console\Question\Question; |
||
| 24 | |||
| 25 | |||
| 26 | class RunCommand extends Command |
||
| 27 | { |
||
| 28 | |||
| 29 | protected function configure() |
||
| 30 | { |
||
| 31 | $this |
||
| 32 | // the name of the command (the part after "bin/console") |
||
| 33 | ->setName('run') |
||
| 34 | ->setDescription('Run Mokka! Run!') |
||
| 35 | ->addOption('market', 'm', InputOption::VALUE_OPTIONAL, 'Choose market to run', 'binance') |
||
| 36 | ->addOption('interval', 'i', InputOption::VALUE_OPTIONAL, 'Seconds for each requests. Default: 60', 60) |
||
| 37 | ->addOption('symbol', 's', InputOption::VALUE_OPTIONAL, 'Symbol for the bot to run', 'BTCUSDT') |
||
| 38 | ->addOption('indicator', 'it', InputOption::VALUE_OPTIONAL, 'Which indicator will be applied? (for future development)', 'percent') |
||
| 39 | ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'default config file. you can use custom config for each command', 'default') |
||
| 40 | ->addOption('test', 't', InputOption::VALUE_OPTIONAL, 'Test mode for botta. If set TRUE botta will not buy and sell any crypto currency', false) |
||
| 41 | |||
| 42 | ; |
||
| 43 | } |
||
| 44 | |||
| 45 | /** |
||
| 46 | * @param InputInterface $input |
||
| 47 | * @param OutputInterface $output |
||
| 48 | * @return int|null|void |
||
| 49 | * @throws \Symfony\Component\Debug\Exception\ClassNotFoundException |
||
| 50 | */ |
||
| 51 | protected function execute(InputInterface $input, OutputInterface $output) |
||
| 52 | { |
||
| 53 | //get config first |
||
| 54 | try { |
||
| 55 | $config = (new Configurator(__DIR__.'/../../config/'.$input->getOption('config').'.yml'))->make(); |
||
| 56 | |||
| 57 | //check if Exchange Market provider is available |
||
| 58 | $marketConfig = $config->get('markets.'.$input->getOption('market')); |
||
| 59 | $market = (new ExchangeFactory($input->getOption('market')))->make([$marketConfig]); |
||
| 60 | |||
| 61 | //set logs (txt db) |
||
| 62 | $logFileType = |
||
| 63 | $config->get('mokka.default_log_type') == 'date' |
||
| 64 | ? (new \DateTime())->format('Y-m-d') |
||
| 65 | : $input->getOption('symbol'); |
||
| 66 | |||
| 67 | $logger = new Logger(__DIR__.'/../../logs/', $logFileType); |
||
| 68 | |||
| 69 | //check the first row in logs |
||
| 70 | $this->createActionFile($logger, $input, $output); |
||
| 71 | |||
| 72 | //get indicator |
||
| 73 | $indicatorConfig = $config->get('indicators.'.$input->getOption('indicator')); |
||
| 74 | $indicator = (new IndicatorFactory($input->getOption('indicator'))) |
||
| 75 | ->make([$market, $logger, $indicatorConfig]); |
||
| 76 | |||
| 77 | |||
| 78 | //run strategy calculator |
||
| 79 | $strategy = new StrategyCalculator($market, $indicator); |
||
| 80 | |||
| 81 | $strategy->setInterval($input->getOption('interval')); |
||
| 82 | $strategy->setSymbol($input->getOption('symbol')); |
||
| 83 | $strategy->setMarket($input->getOption('market')); |
||
| 84 | |||
| 85 | $output->writeln('<info>Mokka Started!</info>'); |
||
| 86 | $table = new Table($output); |
||
| 87 | $table->setHeaders(array('Action', 'Previous Price', 'Action Price', 'Symbol', 'Amount', 'Trigger', 'Change', 'Date')); |
||
| 88 | |||
| 89 | while (1) { |
||
| 90 | $quantity = new Quantity(); |
||
| 91 | $action = $strategy->run($logger); |
||
| 92 | |||
| 93 | if ($input->getOption('test') === false) { |
||
| 94 | if ($action->getType() == ActionInterface::TYPE_BUY) { |
||
| 95 | //calculate quantity |
||
| 96 | $maxFund = $config->get('markets.'.$input->getOption('market').'.max_fund'); |
||
| 97 | |||
| 98 | /** @var BuyAction $action */ |
||
| 99 | $action->setQuantity( |
||
| 100 | $quantity->buyQuantityCalculator($maxFund, $action->getActionPrice(), $market->getBalance()) |
||
| 101 | ); |
||
| 102 | |||
| 103 | $market->buyOrder($action); |
||
| 104 | } |
||
| 105 | |||
| 106 | |||
| 107 | if ($action->getType() == ActionInterface::TYPE_SELL) { |
||
| 108 | //get quantity to sell |
||
| 109 | $maxSell = $config->get('markets.'.$input->getOption('market').'.max_sell'); |
||
| 110 | |||
| 111 | $action->setQuantity( |
||
| 112 | $quantity->sellQuantityCalculator($maxSell, $action->getQuantity()) |
||
| 113 | ); |
||
| 114 | |||
| 115 | /** @var SellAction $action */ |
||
| 116 | $market->sellOrder($action); |
||
| 117 | } |
||
| 118 | } |
||
| 119 | |||
| 120 | //log the action |
||
| 121 | if ($action->getType() != ActionInterface::TYPE_IDLE) { |
||
| 122 | $logger->insert()->set($action->toArray())->execute(); |
||
| 123 | } |
||
| 124 | |||
| 125 | $table->setRows(array( |
||
| 126 | array( |
||
| 127 | $action->getType(), |
||
| 128 | $action->getPreviousPrice(), |
||
| 129 | $action->getActionPrice(), |
||
| 130 | $action->getSymbol(), |
||
| 131 | $action->getQuantity(), |
||
| 132 | $config->get('indicators.percent.default_percent'), |
||
| 133 | round($action->getActionPrice() / $action->getPreviousPrice(), 5), |
||
| 134 | date('Y-m-d H:i:s') |
||
| 135 | ), |
||
| 136 | )); |
||
| 137 | |||
| 138 | $table->render(); |
||
| 139 | |||
| 140 | sleep($input->getOption('interval')); |
||
| 141 | } |
||
| 142 | |||
| 143 | $output->writeln('<question>Mokka stopped!</question>'); |
||
| 144 | |||
| 145 | } catch (InvalidConfigurationException $exception) { |
||
| 146 | $output->writeln("<error>Invalid Configuration</error>"); |
||
| 147 | } catch (\Exception $exception) { |
||
| 148 | $output->writeln("<error>{$exception->getMessage()}</error>"); |
||
| 149 | } |
||
| 150 | } |
||
| 151 | |||
| 152 | /** |
||
| 153 | * @param Logger $logger |
||
| 154 | * @param InputInterface $input |
||
| 155 | * @param OutputInterface $output |
||
| 156 | * @return array |
||
| 157 | * @internal param Logger $action |
||
| 158 | */ |
||
| 159 | protected function createActionFile(Logger $logger, InputInterface $input, OutputInterface $output) |
||
| 160 | { |
||
| 161 | |||
| 162 | $lastAction = $logger |
||
|
0 ignored issues
–
show
|
|||
| 163 | ->read() |
||
| 164 | ->where('market', '=', $input->getOption('market')) |
||
| 165 | ->where('symbol', '=', $input->getOption('symbol')) |
||
| 166 | ->sortDesc('lastUpdate') |
||
| 167 | ->limit(1) |
||
| 168 | ->first(); |
||
| 169 | |||
| 170 | if ($lastAction) { |
||
|
0 ignored issues
–
show
|
|||
| 171 | return; |
||
| 172 | } |
||
| 173 | |||
| 174 | $helper = $this->getHelper('question'); |
||
| 175 | |||
| 176 | $question1 = new ChoiceQuestion( |
||
| 177 | "We need to know your last transaction. Please check the market ({$input->getOption('market')}) and set your last action for {$input->getOption('symbol')}.", |
||
| 178 | array('buy', 'sell'), |
||
| 179 | 0 |
||
| 180 | ); |
||
| 181 | |||
| 182 | $question1->setErrorMessage('Your response is invalid.'); |
||
| 183 | $chosenActionType = $helper->ask($input, $output, $question1); |
||
| 184 | |||
| 185 | |||
| 186 | $question2 = new Question("What was the last price for {$input->getOption('symbol')}?"); |
||
| 187 | $price = $helper->ask($input, $output, $question2); |
||
| 188 | |||
| 189 | if (!$price) { |
||
| 190 | $output->writeln("<comment>You need to tell me the last action price. Otherwise I can not move on.</comment>"); |
||
| 191 | die(); |
||
|
0 ignored issues
–
show
|
|||
| 192 | } |
||
| 193 | |||
| 194 | $actionContent = new Action(); |
||
| 195 | $actionContent->setType($chosenActionType); |
||
| 196 | $actionContent->setSymbol($input->getOption('symbol')); |
||
| 197 | $actionContent->setLastUpdate(time()); |
||
| 198 | $actionContent->setMarket($input->getOption('market')); |
||
| 199 | $actionContent->setPreviousPrice($price); |
||
| 200 | $actionContent->setActionPrice($price); |
||
| 201 | |||
| 202 | $output->writeln("<info>OK. I know what to do now ;) .</info>"); |
||
| 203 | $logger->insert()->set($actionContent->toArray())->execute(); |
||
| 204 | |||
| 205 | return (array) $actionContent; |
||
| 206 | } |
||
| 207 | |||
| 208 | |||
| 209 | } |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.